]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/initutils.c
2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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.
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.
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
24 #include <sys/prctl.h>
26 #include "initutils.h"
29 lxc_log_define(lxc_initutils
, lxc
);
31 static int mount_fs(const char *source
, const char *target
, const char *type
)
33 /* the umount may fail */
35 WARN("Failed to unmount %s : %s", target
, strerror(errno
));
37 if (mount(source
, target
, type
, 0, NULL
)) {
38 ERROR("Failed to mount %s : %s", target
, strerror(errno
));
42 DEBUG("'%s' mounted on '%s'", source
, target
);
47 extern void lxc_setup_fs(void)
49 if (mount_fs("proc", "/proc", "proc"))
50 INFO("Failed to remount proc");
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");
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");
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'");
67 /* continue even without posix message queue support */
68 if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
69 INFO("Failed to mount /dev/mqueue");
72 static char *copy_global_config_value(char *p
)
79 if (p
[len
-1] == '\n') {
83 retbuf
= malloc(len
+1);
90 const char *lxc_global_config_value(const char *option_name
)
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
},
104 /* placed in the thread local storage pool for non-bionic targets */
106 static __thread
const char *values
[sizeof(options
) / sizeof(options
[0])] = { 0 };
108 static const char *values
[sizeof(options
) / sizeof(options
[0])] = { 0 };
111 /* user_config_path is freed as soon as it is used */
112 char *user_config_path
= NULL
;
115 * The following variables are freed at bottom unconditionally.
116 * So NULL the value if it is to be returned to the caller
118 char *user_default_config_path
= NULL
;
119 char *user_lxc_path
= NULL
;
120 char *user_cgroup_pattern
= NULL
;
123 const char *user_home
= getenv("HOME");
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
)));
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");
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
);
143 const char * const (*ptr
)[2];
145 char buf
[1024], *p
, *p2
;
148 for (i
= 0, ptr
= options
; (*ptr
)[0]; ptr
++, i
++) {
149 if (!strcmp(option_name
, (*ptr
)[0]))
153 free(user_config_path
);
154 free(user_default_config_path
);
156 free(user_cgroup_pattern
);
162 free(user_config_path
);
163 free(user_default_config_path
);
165 free(user_cgroup_pattern
);
169 fin
= fopen_cloexec(user_config_path
, "r");
170 free(user_config_path
);
172 while (fgets(buf
, 1024, fin
)) {
175 p
= strstr(buf
, option_name
);
178 /* see if there was just white space in front
181 for (p2
= buf
; p2
< p
; p2
++) {
182 if (*p2
!= ' ' && *p2
!= '\t')
190 /* see if there was just white space after
193 for (p2
+= strlen(option_name
); p2
< p
; p2
++) {
194 if (*p2
!= ' ' && *p2
!= '\t')
200 while (*p
&& (*p
== ' ' || *p
== '\t')) p
++;
204 if (strcmp(option_name
, "lxc.lxcpath") == 0) {
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
;
213 values
[i
] = copy_global_config_value(p
);
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
;
223 else if (strcmp(option_name
, "lxc.default_config") == 0) {
224 values
[i
] = user_default_config_path
;
225 user_default_config_path
= NULL
;
227 else if (strcmp(option_name
, "lxc.cgroup.pattern") == 0) {
228 values
[i
] = user_cgroup_pattern
;
229 user_cgroup_pattern
= NULL
;
232 values
[i
] = (*ptr
)[1];
234 /* special case: if default value is NULL,
235 * and there is no config, don't view that
244 free(user_cgroup_pattern
);
245 free(user_default_config_path
);
251 extern void remove_trailing_slashes(char *p
)
254 while (--l
>= 0 && (p
[l
] == '/' || p
[l
] == '\n'))
258 FILE *fopen_cloexec(const char *path
, const char *mode
)
266 if (!strncmp(mode
, "r+", 2)) {
269 } else if (!strncmp(mode
, "r", 1)) {
270 open_mode
= O_RDONLY
;
272 } else if (!strncmp(mode
, "w+", 2)) {
273 open_mode
= O_RDWR
| O_TRUNC
| O_CREAT
;
275 } else if (!strncmp(mode
, "w", 1)) {
276 open_mode
= O_WRONLY
| O_TRUNC
| O_CREAT
;
278 } else if (!strncmp(mode
, "a+", 2)) {
279 open_mode
= O_RDWR
| O_CREAT
| O_APPEND
;
281 } else if (!strncmp(mode
, "a", 1)) {
282 open_mode
= O_WRONLY
| O_CREAT
| O_APPEND
;
285 for (; mode
[step
]; step
++)
286 if (mode
[step
] == 'x')
288 open_mode
|= O_CLOEXEC
;
290 fd
= open(path
, open_mode
, 0666);
294 ret
= fdopen(fd
, mode
);
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).
306 int setproctitle(char *title
)
308 static char *proctitle
= NULL
;
309 char buf
[2048], *tmp
;
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.
317 unsigned long start_data
, end_data
, start_brk
, start_code
, end_code
,
318 start_stack
, arg_start
, arg_end
, env_start
, env_end
,
320 struct prctl_mm_map prctl_map
;
322 f
= fopen_cloexec("/proc/self/stat", "r");
327 tmp
= fgets(buf
, sizeof(buf
), f
);
333 /* Skip the first 25 fields, column 26-28 are start_code, end_code,
335 tmp
= strchr(buf
, ' ');
336 for (i
= 0; i
< 24; i
++) {
339 tmp
= strchr(tmp
+1, ' ');
344 i
= sscanf(tmp
, "%lu %lu %lu", &start_code
, &end_code
, &start_stack
);
348 /* Skip the next 19 fields, column 45-51 are start_data to arg_end */
349 for (i
= 0; i
< 19; i
++) {
352 tmp
= strchr(tmp
+1, ' ');
358 i
= sscanf(tmp
, "%lu %lu %lu %*u %*u %lu %lu",
367 /* Include the null byte here, because in the calculations below we
368 * want to have room for it. */
369 len
= strlen(title
) + 1;
371 proctitle
= realloc(proctitle
, len
);
375 arg_start
= (unsigned long) proctitle
;
376 arg_end
= arg_start
+ len
;
378 brk_val
= syscall(__NR_brk
, 0);
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
,
388 .arg_start
= arg_start
,
390 .env_start
= env_start
,
397 ret
= prctl(PR_SET_MM
, PR_SET_MM_MAP
, (long) &prctl_map
, sizeof(prctl_map
), 0);
399 strcpy((char*)arg_start
, title
);
401 INFO("setting cmdline failed - %s", strerror(errno
));