]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/utils.c
fopen_cloexec: simplify open call
[mirror_lxc.git] / src / lxc / utils.c
CommitLineData
e3642c43
DL
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
e3642c43
DL
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
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
e3642c43
DL
22 */
23
d983b93c 24#define _GNU_SOURCE
e3642c43
DL
25#include <errno.h>
26#include <unistd.h>
d983b93c
MN
27#include <stdlib.h>
28#include <stddef.h>
61a1d519 29#include <string.h>
e3642c43
DL
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/mman.h>
d983b93c 33#include <sys/param.h>
6e4bb2e0 34#include <sys/mount.h>
d983b93c
MN
35#include <dirent.h>
36#include <fcntl.h>
1b09f2c0 37#include <libgen.h>
9be53773
SH
38#include <sys/types.h>
39#include <sys/wait.h>
e3642c43 40
3ce74686 41#include "utils.h"
e3642c43
DL
42#include "log.h"
43
44lxc_log_define(lxc_utils, lxc);
45
60bf62d4
SH
46static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
47{
48 struct dirent dirent, *direntp;
49 DIR *dir;
50 int ret, failed=0;
51 char pathname[MAXPATHLEN];
52
53 dir = opendir(dirname);
54 if (!dir) {
55 ERROR("%s: failed to open %s", __func__, dirname);
56 return 0;
57 }
58
59 while (!readdir_r(dir, &dirent, &direntp)) {
60 struct stat mystat;
61 int rc;
62
63 if (!direntp)
64 break;
65
66 if (!strcmp(direntp->d_name, ".") ||
67 !strcmp(direntp->d_name, ".."))
68 continue;
69
70 rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
71 if (rc < 0 || rc >= MAXPATHLEN) {
72 ERROR("pathname too long");
73 failed=1;
74 continue;
75 }
76 ret = lstat(pathname, &mystat);
77 if (ret) {
78 ERROR("%s: failed to stat %s", __func__, pathname);
79 failed=1;
80 continue;
81 }
82 if (mystat.st_dev != pdev)
83 continue;
84 if (S_ISDIR(mystat.st_mode)) {
85 if (!_recursive_rmdir_onedev(pathname, pdev))
86 failed=1;
87 } else {
88 if (unlink(pathname) < 0) {
89 ERROR("%s: failed to delete %s", __func__, pathname);
90 failed=1;
91 }
92 }
93 }
94
95 if (rmdir(dirname) < 0) {
96 ERROR("%s: failed to delete %s", __func__, dirname);
97 failed=1;
98 }
99
100 if (closedir(dir)) {
101 ERROR("%s: failed to close directory %s", __func__, dirname);
102 failed=1;
103 }
104
105 return !failed;
106}
107
108/* returns 1 on success, 0 if there were any failures */
109extern int lxc_rmdir_onedev(char *path)
110{
111 struct stat mystat;
112
113 if (lstat(path, &mystat) < 0) {
114 ERROR("%s: failed to stat %s", __func__, path);
115 return 0;
116 }
117
118 return _recursive_rmdir_onedev(path, mystat.st_dev);
119}
120
6e4bb2e0
MN
121static int mount_fs(const char *source, const char *target, const char *type)
122{
123 /* the umount may fail */
124 if (umount(target))
125 WARN("failed to unmount %s : %s", target, strerror(errno));
126
127 if (mount(source, target, type, 0, NULL)) {
128 ERROR("failed to mount %s : %s", target, strerror(errno));
129 return -1;
130 }
131
132 DEBUG("'%s' mounted on '%s'", source, target);
133
134 return 0;
135}
136
137extern int lxc_setup_fs(void)
138{
139 if (mount_fs("proc", "/proc", "proc"))
140 return -1;
141
721d262c 142 /* if we can't mount /dev/shm, continue anyway */
6e4bb2e0 143 if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
3283db09 144 INFO("failed to mount /dev/shm");
6e4bb2e0
MN
145
146 /* If we were able to mount /dev/shm, then /dev exists */
b91b1cd7 147 /* Sure, but it's read-only per config :) */
6e4bb2e0 148 if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
b91b1cd7
SH
149 DEBUG("failed to create '/dev/mqueue'");
150 return 0;
6e4bb2e0
MN
151 }
152
5d4d3ebb 153 /* continue even without posix message queue support */
6e4bb2e0 154 if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
5d4d3ebb 155 INFO("failed to mount /dev/mqueue");
6e4bb2e0
MN
156
157 return 0;
158}
9ddaf3bf
JHS
159
160/* borrowed from iproute2 */
7c11d57a 161extern int get_u16(unsigned short *val, const char *arg, int base)
9ddaf3bf
JHS
162{
163 unsigned long res;
164 char *ptr;
165
166 if (!arg || !*arg)
167 return -1;
168
169 res = strtoul(arg, &ptr, base);
170 if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
171 return -1;
172
173 *val = res;
174
175 return 0;
176}
177
3ce74686 178extern int mkdir_p(const char *dir, mode_t mode)
1b09f2c0 179{
3ce74686
SH
180 const char *tmp = dir;
181 const char *orig = dir;
860fc865
RW
182 char *makeme;
183
184 do {
185 dir = tmp + strspn(tmp, "/");
186 tmp = dir + strcspn(dir, "/");
d74325c4 187 makeme = strndup(orig, dir - orig);
860fc865
RW
188 if (*makeme) {
189 if (mkdir(makeme, mode) && errno != EEXIST) {
190 SYSERROR("failed to create directory '%s'\n", makeme);
d74325c4 191 free(makeme);
860fc865
RW
192 return -1;
193 }
194 }
d74325c4 195 free(makeme);
860fc865 196 } while(tmp != dir);
1b09f2c0 197
98663823 198 return 0;
1b09f2c0 199}
2a59a681 200
d0386d66 201static char *copy_global_config_value(char *p)
2a59a681
SH
202{
203 int len = strlen(p);
204 char *retbuf;
205
206 if (len < 1)
207 return NULL;
208 if (p[len-1] == '\n') {
209 p[len-1] = '\0';
210 len--;
211 }
212 retbuf = malloc(len+1);
213 if (!retbuf)
214 return NULL;
215 strcpy(retbuf, p);
216 return retbuf;
217}
218
31a95fec 219#define DEFAULT_VG "lxc"
31a95fec 220#define DEFAULT_ZFSROOT "lxc"
67e571de 221
d0386d66 222const char *lxc_global_config_value(const char *option_name)
31a95fec 223{
d0386d66
CS
224 static const char *options[][2] = {
225 { "lvm_vg", DEFAULT_VG },
226 { "zfsroot", DEFAULT_ZFSROOT },
227 { "lxcpath", LXCPATH },
6e16552d 228 { "cgroup.pattern", DEFAULT_CGROUP_PATTERN },
d0386d66
CS
229 { NULL, NULL },
230 };
231 static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
232 const char *(*ptr)[2];
233 size_t i;
234 char buf[1024], *p, *p2;
235 FILE *fin = NULL;
236
237 for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
238 if (!strcmp(option_name, (*ptr)[0]))
239 break;
240 }
241 if (!(*ptr)[0]) {
242 errno = EINVAL;
243 return NULL;
244 }
245 if (values[i])
246 return values[i];
31a95fec 247
db27c8d7 248 fin = fopen_cloexec(LXC_GLOBAL_CONF, "r");
31a95fec
SH
249 if (fin) {
250 while (fgets(buf, 1024, fin)) {
251 if (buf[0] == '#')
252 continue;
d0386d66 253 p = strstr(buf, option_name);
31a95fec
SH
254 if (!p)
255 continue;
d0386d66
CS
256 /* see if there was just white space in front
257 * of the option name
258 */
259 for (p2 = buf; p2 < p; p2++) {
260 if (*p2 != ' ' && *p2 != '\t')
261 break;
262 }
263 if (p2 < p)
264 continue;
31a95fec
SH
265 p = strchr(p, '=');
266 if (!p)
267 continue;
d0386d66
CS
268 /* see if there was just white space after
269 * the option name
270 */
271 for (p2 += strlen(option_name); p2 < p; p2++) {
272 if (*p2 != ' ' && *p2 != '\t')
273 break;
274 }
275 if (p2 < p)
276 continue;
31a95fec
SH
277 p++;
278 while (*p && (*p == ' ' || *p == '\t')) p++;
279 if (!*p)
280 continue;
d0386d66 281 values[i] = copy_global_config_value(p);
31a95fec
SH
282 goto out;
283 }
284 }
d0386d66
CS
285 /* could not find value, use default */
286 values[i] = (*ptr)[1];
287 /* special case: if default value is NULL,
288 * and there is no config, don't view that
289 * as an error... */
290 if (!values[i])
291 errno = 0;
31a95fec
SH
292
293out:
294 if (fin)
295 fclose(fin);
d0386d66 296 return values[i];
31a95fec
SH
297}
298
d0386d66 299const char *default_lvm_vg(void)
31a95fec 300{
d0386d66
CS
301 return lxc_global_config_value("lvm_vg");
302}
31a95fec 303
d0386d66
CS
304const char *default_zfs_root(void)
305{
306 return lxc_global_config_value("zfsroot");
31a95fec 307}
67e571de 308const char *default_lxc_path(void)
2a59a681 309{
d0386d66 310 return lxc_global_config_value("lxcpath");
2a59a681 311}
9be53773
SH
312
313int wait_for_pid(pid_t pid)
314{
315 int status, ret;
316
317again:
318 ret = waitpid(pid, &status, 0);
319 if (ret == -1) {
71b9b8ed 320 if (errno == EINTR)
9be53773
SH
321 goto again;
322 return -1;
323 }
324 if (ret != pid)
325 goto again;
326 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
327 return -1;
328 return 0;
329}
c797a220
CS
330
331int lxc_wait_for_pid_status(pid_t pid)
332{
333 int status, ret;
334
335again:
336 ret = waitpid(pid, &status, 0);
337 if (ret == -1) {
338 if (errno == EINTR)
339 goto again;
340 return -1;
341 }
342 if (ret != pid)
343 goto again;
344 return status;
345}
92f023dc 346
650468bb 347ssize_t lxc_write_nointr(int fd, const void* buf, size_t count)
92f023dc 348{
650468bb 349 ssize_t ret;
92f023dc
CS
350again:
351 ret = write(fd, buf, count);
352 if (ret < 0 && errno == EINTR)
353 goto again;
354 return ret;
355}
356
650468bb 357ssize_t lxc_read_nointr(int fd, void* buf, size_t count)
92f023dc 358{
650468bb 359 ssize_t ret;
92f023dc
CS
360again:
361 ret = read(fd, buf, count);
362 if (ret < 0 && errno == EINTR)
363 goto again;
364 return ret;
365}
366
650468bb 367ssize_t lxc_read_nointr_expect(int fd, void* buf, size_t count, const void* expected_buf)
92f023dc 368{
650468bb 369 ssize_t ret;
92f023dc
CS
370 ret = lxc_read_nointr(fd, buf, count);
371 if (ret <= 0)
372 return ret;
650468bb 373 if ((size_t)ret != count)
92f023dc
CS
374 return -1;
375 if (expected_buf && memcmp(buf, expected_buf, count) != 0) {
376 errno = EINVAL;
377 return -1;
378 }
379 return ret;
380}
3ce74686
SH
381
382#if HAVE_LIBGNUTLS
383#include <gnutls/gnutls.h>
384#include <gnutls/crypto.h>
385int sha1sum_file(char *fnam, unsigned char *digest)
386{
387 char *buf;
388 int ret;
389 FILE *f;
390 long flen;
391
392 if (!fnam)
393 return -1;
db27c8d7 394 if ((f = fopen_cloexec(fnam, "r")) < 0) {
3ce74686
SH
395 SYSERROR("Error opening template");
396 return -1;
397 }
398 if (fseek(f, 0, SEEK_END) < 0) {
399 SYSERROR("Error seeking to end of template");
400 fclose(f);
401 return -1;
402 }
403 if ((flen = ftell(f)) < 0) {
404 SYSERROR("Error telling size of template");
405 fclose(f);
406 return -1;
407 }
408 if (fseek(f, 0, SEEK_SET) < 0) {
409 SYSERROR("Error seeking to start of template");
410 fclose(f);
411 return -1;
412 }
413 if ((buf = malloc(flen+1)) == NULL) {
414 SYSERROR("Out of memory");
415 fclose(f);
416 return -1;
417 }
418 if (fread(buf, 1, flen, f) != flen) {
419 SYSERROR("Failure reading template");
420 free(buf);
421 fclose(f);
422 return -1;
423 }
424 if (fclose(f) < 0) {
425 SYSERROR("Failre closing template");
426 free(buf);
427 return -1;
428 }
429 buf[flen] = '\0';
430 ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, buf, flen, (void *)digest);
431 free(buf);
432 return ret;
433}
434#endif
61a1d519
CS
435
436char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
437{
438 va_list ap2;
439 size_t count = 1 + skip;
440 char **result;
441
442 /* first determine size of argument list, we don't want to reallocate
443 * constantly...
444 */
445 va_copy(ap2, ap);
446 while (1) {
447 char* arg = va_arg(ap2, char*);
448 if (!arg)
449 break;
450 count++;
451 }
452 va_end(ap2);
453
454 result = calloc(count, sizeof(char*));
455 if (!result)
456 return NULL;
457 count = skip;
458 while (1) {
459 char* arg = va_arg(ap, char*);
460 if (!arg)
461 break;
462 arg = do_strdup ? strdup(arg) : arg;
463 if (!arg)
464 goto oom;
465 result[count++] = arg;
466 }
467
468 /* calloc has already set last element to NULL*/
469 return result;
470
471oom:
472 free(result);
473 return NULL;
474}
475
476const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
477{
478 return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
479}
db27c8d7
CS
480
481FILE *fopen_cloexec(const char *path, const char *mode)
482{
483 int open_mode = 0;
484 int step = 0;
485 int fd;
486 int saved_errno = 0;
487 FILE *ret;
488
489 if (!strncmp(mode, "r+", 2)) {
490 open_mode = O_RDWR;
491 step = 2;
492 } else if (!strncmp(mode, "r", 1)) {
493 open_mode = O_RDONLY;
494 step = 1;
495 } else if (!strncmp(mode, "w+", 2)) {
496 open_mode = O_RDWR | O_TRUNC | O_CREAT;
497 step = 2;
498 } else if (!strncmp(mode, "w", 1)) {
499 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
500 step = 1;
501 } else if (!strncmp(mode, "a+", 2)) {
502 open_mode = O_RDWR | O_CREAT | O_APPEND;
503 step = 2;
504 } else if (!strncmp(mode, "a", 1)) {
505 open_mode = O_WRONLY | O_CREAT | O_APPEND;
506 step = 1;
507 }
508 for (; mode[step]; step++)
509 if (mode[step] == 'x')
510 open_mode |= O_EXCL;
511 open_mode |= O_CLOEXEC;
512
82371fdd 513 fd = open(path, open_mode, 0666);
db27c8d7
CS
514 if (fd < 0)
515 return NULL;
516
517 ret = fdopen(fd, mode);
518 saved_errno = errno;
519 if (!ret)
520 close(fd);
521 errno = saved_errno;
522 return ret;
523}