]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/initutils.c
string_utils: add remove_trailing_slashes()
[mirror_lxc.git] / src / lxc / initutils.c
CommitLineData
4295c5de
SH
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
7874d81a 24#define _GNU_SOURCE
a6f151a7
CB
25#include <sys/prctl.h>
26
37ef15bb 27#include "file_utils.h"
4295c5de
SH
28#include "initutils.h"
29#include "log.h"
b81689a1 30#include "macro.h"
4295c5de 31
43f984ea
DJ
32#ifndef HAVE_STRLCPY
33#include "include/strlcpy.h"
34#endif
35
ac2cecc4 36lxc_log_define(initutils, lxc);
4295c5de 37
4295c5de
SH
38static char *copy_global_config_value(char *p)
39{
40 int len = strlen(p);
41 char *retbuf;
42
43 if (len < 1)
44 return NULL;
43f984ea 45
4295c5de
SH
46 if (p[len-1] == '\n') {
47 p[len-1] = '\0';
48 len--;
49 }
43f984ea
DJ
50
51 retbuf = malloc(len + 1);
4295c5de
SH
52 if (!retbuf)
53 return NULL;
43f984ea
DJ
54
55 (void)strlcpy(retbuf, p, len + 1);
4295c5de
SH
56 return retbuf;
57}
58
59const char *lxc_global_config_value(const char *option_name)
60{
61 static const char * const options[][2] = {
62 { "lxc.bdev.lvm.vg", DEFAULT_VG },
63 { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
64 { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
7da812df 65 { "lxc.bdev.rbd.rbdpool", DEFAULT_RBDPOOL },
4295c5de
SH
66 { "lxc.lxcpath", NULL },
67 { "lxc.default_config", NULL },
68 { "lxc.cgroup.pattern", NULL },
69 { "lxc.cgroup.use", NULL },
70 { NULL, NULL },
71 };
72
73 /* placed in the thread local storage pool for non-bionic targets */
74#ifdef HAVE_TLS
75 static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
76#else
77 static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
78#endif
79
80 /* user_config_path is freed as soon as it is used */
81 char *user_config_path = NULL;
82
83 /*
84 * The following variables are freed at bottom unconditionally.
85 * So NULL the value if it is to be returned to the caller
86 */
87 char *user_default_config_path = NULL;
88 char *user_lxc_path = NULL;
89 char *user_cgroup_pattern = NULL;
90
91 if (geteuid() > 0) {
92 const char *user_home = getenv("HOME");
93 if (!user_home)
94 user_home = "/";
95
96 user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
97 user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
98 user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));
99
100 sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
101 sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
102 sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
103 user_cgroup_pattern = strdup("lxc/%n");
104 }
105 else {
106 user_config_path = strdup(LXC_GLOBAL_CONF);
107 user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
108 user_lxc_path = strdup(LXCPATH);
109 user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
110 }
111
112 const char * const (*ptr)[2];
113 size_t i;
114 char buf[1024], *p, *p2;
115 FILE *fin = NULL;
116
117 for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
118 if (!strcmp(option_name, (*ptr)[0]))
119 break;
120 }
121 if (!(*ptr)[0]) {
122 free(user_config_path);
123 free(user_default_config_path);
124 free(user_lxc_path);
125 free(user_cgroup_pattern);
126 errno = EINVAL;
127 return NULL;
128 }
129
130 if (values[i]) {
131 free(user_config_path);
132 free(user_default_config_path);
133 free(user_lxc_path);
134 free(user_cgroup_pattern);
135 return values[i];
136 }
137
138 fin = fopen_cloexec(user_config_path, "r");
139 free(user_config_path);
140 if (fin) {
141 while (fgets(buf, 1024, fin)) {
142 if (buf[0] == '#')
143 continue;
144 p = strstr(buf, option_name);
145 if (!p)
146 continue;
147 /* see if there was just white space in front
148 * of the option name
149 */
150 for (p2 = buf; p2 < p; p2++) {
151 if (*p2 != ' ' && *p2 != '\t')
152 break;
153 }
154 if (p2 < p)
155 continue;
156 p = strchr(p, '=');
157 if (!p)
158 continue;
159 /* see if there was just white space after
160 * the option name
161 */
162 for (p2 += strlen(option_name); p2 < p; p2++) {
163 if (*p2 != ' ' && *p2 != '\t')
164 break;
165 }
166 if (p2 < p)
167 continue;
168 p++;
169 while (*p && (*p == ' ' || *p == '\t')) p++;
170 if (!*p)
171 continue;
172
173 if (strcmp(option_name, "lxc.lxcpath") == 0) {
174 free(user_lxc_path);
175 user_lxc_path = copy_global_config_value(p);
176 remove_trailing_slashes(user_lxc_path);
177 values[i] = user_lxc_path;
178 user_lxc_path = NULL;
179 goto out;
180 }
181
182 values[i] = copy_global_config_value(p);
183 goto out;
184 }
185 }
186 /* could not find value, use default */
187 if (strcmp(option_name, "lxc.lxcpath") == 0) {
188 remove_trailing_slashes(user_lxc_path);
189 values[i] = user_lxc_path;
190 user_lxc_path = NULL;
191 }
192 else if (strcmp(option_name, "lxc.default_config") == 0) {
193 values[i] = user_default_config_path;
194 user_default_config_path = NULL;
195 }
196 else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
197 values[i] = user_cgroup_pattern;
198 user_cgroup_pattern = NULL;
199 }
200 else
201 values[i] = (*ptr)[1];
202
203 /* special case: if default value is NULL,
204 * and there is no config, don't view that
205 * as an error... */
206 if (!values[i])
207 errno = 0;
208
209out:
210 if (fin)
211 fclose(fin);
212
213 free(user_cgroup_pattern);
214 free(user_default_config_path);
215 free(user_lxc_path);
216
217 return values[i];
218}
219
a6f151a7
CB
220/*
221 * Sets the process title to the specified title. Note that this may fail if
222 * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
223 */
224int setproctitle(char *title)
225{
226 static char *proctitle = NULL;
227 char buf[2048], *tmp;
228 FILE *f;
229 int i, len, ret = 0;
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,
237 brk_val;
238 struct prctl_mm_map prctl_map;
239
240 f = fopen_cloexec("/proc/self/stat", "r");
241 if (!f) {
242 return -1;
243 }
244
245 tmp = fgets(buf, sizeof(buf), f);
246 fclose(f);
247 if (!tmp) {
248 return -1;
249 }
250
251 /* Skip the first 25 fields, column 26-28 are start_code, end_code,
252 * and start_stack */
253 tmp = strchr(buf, ' ');
254 for (i = 0; i < 24; i++) {
255 if (!tmp)
256 return -1;
257 tmp = strchr(tmp+1, ' ');
258 }
259 if (!tmp)
260 return -1;
261
262 i = sscanf(tmp, "%lu %lu %lu", &start_code, &end_code, &start_stack);
263 if (i != 3)
264 return -1;
265
266 /* Skip the next 19 fields, column 45-51 are start_data to arg_end */
267 for (i = 0; i < 19; i++) {
268 if (!tmp)
269 return -1;
270 tmp = strchr(tmp+1, ' ');
271 }
272
273 if (!tmp)
274 return -1;
275
276 i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
277 &start_data,
278 &end_data,
279 &start_brk,
280 &env_start,
281 &env_end);
282 if (i != 5)
283 return -1;
284
285 /* Include the null byte here, because in the calculations below we
286 * want to have room for it. */
287 len = strlen(title) + 1;
288
289 proctitle = realloc(proctitle, len);
290 if (!proctitle)
291 return -1;
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
b81689a1
CB
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));
a6f151a7 317 if (ret == 0)
43f984ea 318 (void)strlcpy((char*)arg_start, title, len);
a6f151a7 319 else
7874d81a 320 SYSINFO("setting cmdline failed");
a6f151a7
CB
321
322 return ret;
323}