]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/initutils.c
lxc-start: remove unnecessary checks
[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 #include <sys/prctl.h>
25
26 #include "initutils.h"
27 #include "log.h"
28
29 lxc_log_define(lxc_initutils, lxc);
30
31 static int mount_fs(const char *source, const char *target, const char *type)
32 {
33 /* the umount may fail */
34 if (umount(target))
35 WARN("Failed to unmount %s : %s", target, strerror(errno));
36
37 if (mount(source, target, type, 0, NULL)) {
38 ERROR("Failed to mount %s : %s", target, strerror(errno));
39 return -1;
40 }
41
42 DEBUG("'%s' mounted on '%s'", source, target);
43
44 return 0;
45 }
46
47 extern void lxc_setup_fs(void)
48 {
49 if (mount_fs("proc", "/proc", "proc"))
50 INFO("Failed to remount proc");
51
52 /* if /dev has been populated by us, /dev/shm does not exist */
53 if (access("/dev/shm", F_OK) && mkdir("/dev/shm", 0777))
54 INFO("Failed to create /dev/shm");
55
56 /* if we can't mount /dev/shm, continue anyway */
57 if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
58 INFO("Failed to mount /dev/shm");
59
60 /* If we were able to mount /dev/shm, then /dev exists */
61 /* Sure, but it's read-only per config :) */
62 if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
63 DEBUG("Failed to create '/dev/mqueue'");
64 return;
65 }
66
67 /* continue even without posix message queue support */
68 if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
69 INFO("Failed to mount /dev/mqueue");
70 }
71
72 static char *copy_global_config_value(char *p)
73 {
74 int len = strlen(p);
75 char *retbuf;
76
77 if (len < 1)
78 return NULL;
79 if (p[len-1] == '\n') {
80 p[len-1] = '\0';
81 len--;
82 }
83 retbuf = malloc(len+1);
84 if (!retbuf)
85 return NULL;
86 strcpy(retbuf, p);
87 return retbuf;
88 }
89
90 const char *lxc_global_config_value(const char *option_name)
91 {
92 static const char * const options[][2] = {
93 { "lxc.bdev.lvm.vg", DEFAULT_VG },
94 { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
95 { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
96 { "lxc.bdev.rbd.rbdpool", DEFAULT_RBDPOOL },
97 { "lxc.lxcpath", NULL },
98 { "lxc.default_config", NULL },
99 { "lxc.cgroup.pattern", NULL },
100 { "lxc.cgroup.use", NULL },
101 { NULL, NULL },
102 };
103
104 /* placed in the thread local storage pool for non-bionic targets */
105 #ifdef HAVE_TLS
106 static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
107 #else
108 static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
109 #endif
110
111 /* user_config_path is freed as soon as it is used */
112 char *user_config_path = NULL;
113
114 /*
115 * The following variables are freed at bottom unconditionally.
116 * So NULL the value if it is to be returned to the caller
117 */
118 char *user_default_config_path = NULL;
119 char *user_lxc_path = NULL;
120 char *user_cgroup_pattern = NULL;
121
122 if (geteuid() > 0) {
123 const char *user_home = getenv("HOME");
124 if (!user_home)
125 user_home = "/";
126
127 user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
128 user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
129 user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));
130
131 sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
132 sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
133 sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
134 user_cgroup_pattern = strdup("lxc/%n");
135 }
136 else {
137 user_config_path = strdup(LXC_GLOBAL_CONF);
138 user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
139 user_lxc_path = strdup(LXCPATH);
140 user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
141 }
142
143 const char * const (*ptr)[2];
144 size_t i;
145 char buf[1024], *p, *p2;
146 FILE *fin = NULL;
147
148 for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
149 if (!strcmp(option_name, (*ptr)[0]))
150 break;
151 }
152 if (!(*ptr)[0]) {
153 free(user_config_path);
154 free(user_default_config_path);
155 free(user_lxc_path);
156 free(user_cgroup_pattern);
157 errno = EINVAL;
158 return NULL;
159 }
160
161 if (values[i]) {
162 free(user_config_path);
163 free(user_default_config_path);
164 free(user_lxc_path);
165 free(user_cgroup_pattern);
166 return values[i];
167 }
168
169 fin = fopen_cloexec(user_config_path, "r");
170 free(user_config_path);
171 if (fin) {
172 while (fgets(buf, 1024, fin)) {
173 if (buf[0] == '#')
174 continue;
175 p = strstr(buf, option_name);
176 if (!p)
177 continue;
178 /* see if there was just white space in front
179 * of the option name
180 */
181 for (p2 = buf; p2 < p; p2++) {
182 if (*p2 != ' ' && *p2 != '\t')
183 break;
184 }
185 if (p2 < p)
186 continue;
187 p = strchr(p, '=');
188 if (!p)
189 continue;
190 /* see if there was just white space after
191 * the option name
192 */
193 for (p2 += strlen(option_name); p2 < p; p2++) {
194 if (*p2 != ' ' && *p2 != '\t')
195 break;
196 }
197 if (p2 < p)
198 continue;
199 p++;
200 while (*p && (*p == ' ' || *p == '\t')) p++;
201 if (!*p)
202 continue;
203
204 if (strcmp(option_name, "lxc.lxcpath") == 0) {
205 free(user_lxc_path);
206 user_lxc_path = copy_global_config_value(p);
207 remove_trailing_slashes(user_lxc_path);
208 values[i] = user_lxc_path;
209 user_lxc_path = NULL;
210 goto out;
211 }
212
213 values[i] = copy_global_config_value(p);
214 goto out;
215 }
216 }
217 /* could not find value, use default */
218 if (strcmp(option_name, "lxc.lxcpath") == 0) {
219 remove_trailing_slashes(user_lxc_path);
220 values[i] = user_lxc_path;
221 user_lxc_path = NULL;
222 }
223 else if (strcmp(option_name, "lxc.default_config") == 0) {
224 values[i] = user_default_config_path;
225 user_default_config_path = NULL;
226 }
227 else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
228 values[i] = user_cgroup_pattern;
229 user_cgroup_pattern = NULL;
230 }
231 else
232 values[i] = (*ptr)[1];
233
234 /* special case: if default value is NULL,
235 * and there is no config, don't view that
236 * as an error... */
237 if (!values[i])
238 errno = 0;
239
240 out:
241 if (fin)
242 fclose(fin);
243
244 free(user_cgroup_pattern);
245 free(user_default_config_path);
246 free(user_lxc_path);
247
248 return values[i];
249 }
250
251 extern void remove_trailing_slashes(char *p)
252 {
253 int l = strlen(p);
254 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
255 p[l] = '\0';
256 }
257
258 FILE *fopen_cloexec(const char *path, const char *mode)
259 {
260 int open_mode = 0;
261 int step = 0;
262 int fd;
263 int saved_errno = 0;
264 FILE *ret;
265
266 if (!strncmp(mode, "r+", 2)) {
267 open_mode = O_RDWR;
268 step = 2;
269 } else if (!strncmp(mode, "r", 1)) {
270 open_mode = O_RDONLY;
271 step = 1;
272 } else if (!strncmp(mode, "w+", 2)) {
273 open_mode = O_RDWR | O_TRUNC | O_CREAT;
274 step = 2;
275 } else if (!strncmp(mode, "w", 1)) {
276 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
277 step = 1;
278 } else if (!strncmp(mode, "a+", 2)) {
279 open_mode = O_RDWR | O_CREAT | O_APPEND;
280 step = 2;
281 } else if (!strncmp(mode, "a", 1)) {
282 open_mode = O_WRONLY | O_CREAT | O_APPEND;
283 step = 1;
284 }
285 for (; mode[step]; step++)
286 if (mode[step] == 'x')
287 open_mode |= O_EXCL;
288 open_mode |= O_CLOEXEC;
289
290 fd = open(path, open_mode, 0666);
291 if (fd < 0)
292 return NULL;
293
294 ret = fdopen(fd, mode);
295 saved_errno = errno;
296 if (!ret)
297 close(fd);
298 errno = saved_errno;
299 return ret;
300 }
301
302 /*
303 * Sets the process title to the specified title. Note that this may fail if
304 * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
305 */
306 int setproctitle(char *title)
307 {
308 static char *proctitle = NULL;
309 char buf[2048], *tmp;
310 FILE *f;
311 int i, len, ret = 0;
312
313 /* We don't really need to know all of this stuff, but unfortunately
314 * PR_SET_MM_MAP requires us to set it all at once, so we have to
315 * figure it out anyway.
316 */
317 unsigned long start_data, end_data, start_brk, start_code, end_code,
318 start_stack, arg_start, arg_end, env_start, env_end,
319 brk_val;
320 struct prctl_mm_map prctl_map;
321
322 f = fopen_cloexec("/proc/self/stat", "r");
323 if (!f) {
324 return -1;
325 }
326
327 tmp = fgets(buf, sizeof(buf), f);
328 fclose(f);
329 if (!tmp) {
330 return -1;
331 }
332
333 /* Skip the first 25 fields, column 26-28 are start_code, end_code,
334 * and start_stack */
335 tmp = strchr(buf, ' ');
336 for (i = 0; i < 24; i++) {
337 if (!tmp)
338 return -1;
339 tmp = strchr(tmp+1, ' ');
340 }
341 if (!tmp)
342 return -1;
343
344 i = sscanf(tmp, "%lu %lu %lu", &start_code, &end_code, &start_stack);
345 if (i != 3)
346 return -1;
347
348 /* Skip the next 19 fields, column 45-51 are start_data to arg_end */
349 for (i = 0; i < 19; i++) {
350 if (!tmp)
351 return -1;
352 tmp = strchr(tmp+1, ' ');
353 }
354
355 if (!tmp)
356 return -1;
357
358 i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
359 &start_data,
360 &end_data,
361 &start_brk,
362 &env_start,
363 &env_end);
364 if (i != 5)
365 return -1;
366
367 /* Include the null byte here, because in the calculations below we
368 * want to have room for it. */
369 len = strlen(title) + 1;
370
371 proctitle = realloc(proctitle, len);
372 if (!proctitle)
373 return -1;
374
375 arg_start = (unsigned long) proctitle;
376 arg_end = arg_start + len;
377
378 brk_val = syscall(__NR_brk, 0);
379
380 prctl_map = (struct prctl_mm_map) {
381 .start_code = start_code,
382 .end_code = end_code,
383 .start_stack = start_stack,
384 .start_data = start_data,
385 .end_data = end_data,
386 .start_brk = start_brk,
387 .brk = brk_val,
388 .arg_start = arg_start,
389 .arg_end = arg_end,
390 .env_start = env_start,
391 .env_end = env_end,
392 .auxv = NULL,
393 .auxv_size = 0,
394 .exe_fd = -1,
395 };
396
397 ret = prctl(PR_SET_MM, PR_SET_MM_MAP, (long) &prctl_map, sizeof(prctl_map), 0);
398 if (ret == 0)
399 strcpy((char*)arg_start, title);
400 else
401 INFO("setting cmdline failed - %s", strerror(errno));
402
403 return ret;
404 }