]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/initutils.c
Merge pull request #1756 from brauner/2017-08-10/further_lxc_2.1_preparations
[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 "initutils.h"
25 #include "log.h"
26
27 lxc_log_define(lxc_initutils, lxc);
28
29 static int mount_fs(const char *source, const char *target, const char *type)
30 {
31 /* the umount may fail */
32 if (umount(target))
33 WARN("Failed to unmount %s : %s", target, strerror(errno));
34
35 if (mount(source, target, type, 0, NULL)) {
36 ERROR("Failed to mount %s : %s", target, strerror(errno));
37 return -1;
38 }
39
40 DEBUG("'%s' mounted on '%s'", source, target);
41
42 return 0;
43 }
44
45 extern void lxc_setup_fs(void)
46 {
47 if (mount_fs("proc", "/proc", "proc"))
48 INFO("Failed to remount proc");
49
50 /* if /dev has been populated by us, /dev/shm does not exist */
51 if (access("/dev/shm", F_OK) && mkdir("/dev/shm", 0777))
52 INFO("Failed to create /dev/shm");
53
54 /* if we can't mount /dev/shm, continue anyway */
55 if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
56 INFO("Failed to mount /dev/shm");
57
58 /* If we were able to mount /dev/shm, then /dev exists */
59 /* Sure, but it's read-only per config :) */
60 if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
61 DEBUG("Failed to create '/dev/mqueue'");
62 return;
63 }
64
65 /* continue even without posix message queue support */
66 if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
67 INFO("Failed to mount /dev/mqueue");
68 }
69
70 static char *copy_global_config_value(char *p)
71 {
72 int len = strlen(p);
73 char *retbuf;
74
75 if (len < 1)
76 return NULL;
77 if (p[len-1] == '\n') {
78 p[len-1] = '\0';
79 len--;
80 }
81 retbuf = malloc(len+1);
82 if (!retbuf)
83 return NULL;
84 strcpy(retbuf, p);
85 return retbuf;
86 }
87
88 const char *lxc_global_config_value(const char *option_name)
89 {
90 static const char * const options[][2] = {
91 { "lxc.bdev.lvm.vg", DEFAULT_VG },
92 { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
93 { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
94 { "lxc.bdev.rbd.rbdpool", DEFAULT_RBDPOOL },
95 { "lxc.lxcpath", NULL },
96 { "lxc.default_config", NULL },
97 { "lxc.cgroup.pattern", NULL },
98 { "lxc.cgroup.use", NULL },
99 { NULL, NULL },
100 };
101
102 /* placed in the thread local storage pool for non-bionic targets */
103 #ifdef HAVE_TLS
104 static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
105 #else
106 static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
107 #endif
108
109 /* user_config_path is freed as soon as it is used */
110 char *user_config_path = NULL;
111
112 /*
113 * The following variables are freed at bottom unconditionally.
114 * So NULL the value if it is to be returned to the caller
115 */
116 char *user_default_config_path = NULL;
117 char *user_lxc_path = NULL;
118 char *user_cgroup_pattern = NULL;
119
120 if (geteuid() > 0) {
121 const char *user_home = getenv("HOME");
122 if (!user_home)
123 user_home = "/";
124
125 user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
126 user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
127 user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));
128
129 sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
130 sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
131 sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
132 user_cgroup_pattern = strdup("lxc/%n");
133 }
134 else {
135 user_config_path = strdup(LXC_GLOBAL_CONF);
136 user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
137 user_lxc_path = strdup(LXCPATH);
138 user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
139 }
140
141 const char * const (*ptr)[2];
142 size_t i;
143 char buf[1024], *p, *p2;
144 FILE *fin = NULL;
145
146 for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
147 if (!strcmp(option_name, (*ptr)[0]))
148 break;
149 }
150 if (!(*ptr)[0]) {
151 free(user_config_path);
152 free(user_default_config_path);
153 free(user_lxc_path);
154 free(user_cgroup_pattern);
155 errno = EINVAL;
156 return NULL;
157 }
158
159 if (values[i]) {
160 free(user_config_path);
161 free(user_default_config_path);
162 free(user_lxc_path);
163 free(user_cgroup_pattern);
164 return values[i];
165 }
166
167 fin = fopen_cloexec(user_config_path, "r");
168 free(user_config_path);
169 if (fin) {
170 while (fgets(buf, 1024, fin)) {
171 if (buf[0] == '#')
172 continue;
173 p = strstr(buf, option_name);
174 if (!p)
175 continue;
176 /* see if there was just white space in front
177 * of the option name
178 */
179 for (p2 = buf; p2 < p; p2++) {
180 if (*p2 != ' ' && *p2 != '\t')
181 break;
182 }
183 if (p2 < p)
184 continue;
185 p = strchr(p, '=');
186 if (!p)
187 continue;
188 /* see if there was just white space after
189 * the option name
190 */
191 for (p2 += strlen(option_name); p2 < p; p2++) {
192 if (*p2 != ' ' && *p2 != '\t')
193 break;
194 }
195 if (p2 < p)
196 continue;
197 p++;
198 while (*p && (*p == ' ' || *p == '\t')) p++;
199 if (!*p)
200 continue;
201
202 if (strcmp(option_name, "lxc.lxcpath") == 0) {
203 free(user_lxc_path);
204 user_lxc_path = copy_global_config_value(p);
205 remove_trailing_slashes(user_lxc_path);
206 values[i] = user_lxc_path;
207 user_lxc_path = NULL;
208 goto out;
209 }
210
211 values[i] = copy_global_config_value(p);
212 goto out;
213 }
214 }
215 /* could not find value, use default */
216 if (strcmp(option_name, "lxc.lxcpath") == 0) {
217 remove_trailing_slashes(user_lxc_path);
218 values[i] = user_lxc_path;
219 user_lxc_path = NULL;
220 }
221 else if (strcmp(option_name, "lxc.default_config") == 0) {
222 values[i] = user_default_config_path;
223 user_default_config_path = NULL;
224 }
225 else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
226 values[i] = user_cgroup_pattern;
227 user_cgroup_pattern = NULL;
228 }
229 else
230 values[i] = (*ptr)[1];
231
232 /* special case: if default value is NULL,
233 * and there is no config, don't view that
234 * as an error... */
235 if (!values[i])
236 errno = 0;
237
238 out:
239 if (fin)
240 fclose(fin);
241
242 free(user_cgroup_pattern);
243 free(user_default_config_path);
244 free(user_lxc_path);
245
246 return values[i];
247 }
248
249 extern void remove_trailing_slashes(char *p)
250 {
251 int l = strlen(p);
252 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
253 p[l] = '\0';
254 }
255
256 FILE *fopen_cloexec(const char *path, const char *mode)
257 {
258 int open_mode = 0;
259 int step = 0;
260 int fd;
261 int saved_errno = 0;
262 FILE *ret;
263
264 if (!strncmp(mode, "r+", 2)) {
265 open_mode = O_RDWR;
266 step = 2;
267 } else if (!strncmp(mode, "r", 1)) {
268 open_mode = O_RDONLY;
269 step = 1;
270 } else if (!strncmp(mode, "w+", 2)) {
271 open_mode = O_RDWR | O_TRUNC | O_CREAT;
272 step = 2;
273 } else if (!strncmp(mode, "w", 1)) {
274 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
275 step = 1;
276 } else if (!strncmp(mode, "a+", 2)) {
277 open_mode = O_RDWR | O_CREAT | O_APPEND;
278 step = 2;
279 } else if (!strncmp(mode, "a", 1)) {
280 open_mode = O_WRONLY | O_CREAT | O_APPEND;
281 step = 1;
282 }
283 for (; mode[step]; step++)
284 if (mode[step] == 'x')
285 open_mode |= O_EXCL;
286 open_mode |= O_CLOEXEC;
287
288 fd = open(path, open_mode, 0666);
289 if (fd < 0)
290 return NULL;
291
292 ret = fdopen(fd, mode);
293 saved_errno = errno;
294 if (!ret)
295 close(fd);
296 errno = saved_errno;
297 return ret;
298 }