]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/utils.c
ubuntu: iproute is now called iproute2
[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
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
SH
200
201static char *copypath(char *p)
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
67e571de 219char *default_lxcpath;
31a95fec
SH
220#define DEFAULT_VG "lxc"
221char *default_lvmvg;
222#define DEFAULT_ZFSROOT "lxc"
223char *default_zfsroot;
67e571de 224
31a95fec
SH
225const char *default_lvm_vg(void)
226{
227 char buf[1024], *p;
228 FILE *fin;
229
230 if (default_lvmvg)
231 return default_lvmvg;
232
233 fin = fopen(LXC_GLOBAL_CONF, "r");
234 if (fin) {
235 while (fgets(buf, 1024, fin)) {
236 if (buf[0] == '#')
237 continue;
238 p = strstr(buf, "lvm_vg");
239 if (!p)
240 continue;
241 p = strchr(p, '=');
242 if (!p)
243 continue;
244 p++;
245 while (*p && (*p == ' ' || *p == '\t')) p++;
246 if (!*p)
247 continue;
248 default_lvmvg = copypath(p);
249 goto out;
250 }
251 }
252 default_lvmvg = DEFAULT_VG;
253
254out:
255 if (fin)
256 fclose(fin);
257 return default_lvmvg;
258}
259
260const char *default_zfs_root(void)
261{
262 char buf[1024], *p;
263 FILE *fin;
264
265 if (default_zfsroot)
266 return default_zfsroot;
267
268 fin = fopen(LXC_GLOBAL_CONF, "r");
269 if (fin) {
270 while (fgets(buf, 1024, fin)) {
271 if (buf[0] == '#')
272 continue;
273 p = strstr(buf, "zfsroot");
274 if (!p)
275 continue;
276 p = strchr(p, '=');
277 if (!p)
278 continue;
279 p++;
280 while (*p && (*p == ' ' || *p == '\t')) p++;
281 if (!*p)
282 continue;
283 default_zfsroot = copypath(p);
284 goto out;
285 }
286 }
287 default_zfsroot = DEFAULT_ZFSROOT;
288
289out:
290 if (fin)
291 fclose(fin);
292 return default_zfsroot;
293}
67e571de 294const char *default_lxc_path(void)
2a59a681 295{
67e571de 296 char buf[1024], *p;
2a59a681
SH
297 FILE *fin;
298
67e571de
SG
299 if (default_lxcpath)
300 return default_lxcpath;
301
2a59a681
SH
302 fin = fopen(LXC_GLOBAL_CONF, "r");
303 if (fin) {
304 while (fgets(buf, 1024, fin)) {
305 if (buf[0] == '#')
306 continue;
307 p = strstr(buf, "lxcpath");
308 if (!p)
309 continue;
310 p = strchr(p, '=');
311 if (!p)
312 continue;
313 p++;
314 while (*p && (*p == ' ' || *p == '\t')) p++;
315 if (!*p)
316 continue;
67e571de 317 default_lxcpath = copypath(p);
2a59a681
SH
318 goto out;
319 }
320 }
321 /* we couldn't open the file, or didn't find a lxcpath
322 * entry there. Return @LXCPATH@ */
67e571de 323 default_lxcpath = LXCPATH;
2a59a681
SH
324
325out:
326 if (fin)
327 fclose(fin);
67e571de 328 return default_lxcpath;
2a59a681 329}
9be53773
SH
330
331int wait_for_pid(pid_t pid)
332{
333 int status, ret;
334
335again:
336 ret = waitpid(pid, &status, 0);
337 if (ret == -1) {
71b9b8ed 338 if (errno == EINTR)
9be53773
SH
339 goto again;
340 return -1;
341 }
342 if (ret != pid)
343 goto again;
344 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
345 return -1;
346 return 0;
347}
c797a220
CS
348
349int lxc_wait_for_pid_status(pid_t pid)
350{
351 int status, ret;
352
353again:
354 ret = waitpid(pid, &status, 0);
355 if (ret == -1) {
356 if (errno == EINTR)
357 goto again;
358 return -1;
359 }
360 if (ret != pid)
361 goto again;
362 return status;
363}
92f023dc 364
650468bb 365ssize_t lxc_write_nointr(int fd, const void* buf, size_t count)
92f023dc 366{
650468bb 367 ssize_t ret;
92f023dc
CS
368again:
369 ret = write(fd, buf, count);
370 if (ret < 0 && errno == EINTR)
371 goto again;
372 return ret;
373}
374
650468bb 375ssize_t lxc_read_nointr(int fd, void* buf, size_t count)
92f023dc 376{
650468bb 377 ssize_t ret;
92f023dc
CS
378again:
379 ret = read(fd, buf, count);
380 if (ret < 0 && errno == EINTR)
381 goto again;
382 return ret;
383}
384
650468bb 385ssize_t lxc_read_nointr_expect(int fd, void* buf, size_t count, const void* expected_buf)
92f023dc 386{
650468bb 387 ssize_t ret;
92f023dc
CS
388 ret = lxc_read_nointr(fd, buf, count);
389 if (ret <= 0)
390 return ret;
650468bb 391 if ((size_t)ret != count)
92f023dc
CS
392 return -1;
393 if (expected_buf && memcmp(buf, expected_buf, count) != 0) {
394 errno = EINVAL;
395 return -1;
396 }
397 return ret;
398}
3ce74686
SH
399
400#if HAVE_LIBGNUTLS
401#include <gnutls/gnutls.h>
402#include <gnutls/crypto.h>
403int sha1sum_file(char *fnam, unsigned char *digest)
404{
405 char *buf;
406 int ret;
407 FILE *f;
408 long flen;
409
410 if (!fnam)
411 return -1;
412 if ((f = fopen(fnam, "r")) < 0) {
413 SYSERROR("Error opening template");
414 return -1;
415 }
416 if (fseek(f, 0, SEEK_END) < 0) {
417 SYSERROR("Error seeking to end of template");
418 fclose(f);
419 return -1;
420 }
421 if ((flen = ftell(f)) < 0) {
422 SYSERROR("Error telling size of template");
423 fclose(f);
424 return -1;
425 }
426 if (fseek(f, 0, SEEK_SET) < 0) {
427 SYSERROR("Error seeking to start of template");
428 fclose(f);
429 return -1;
430 }
431 if ((buf = malloc(flen+1)) == NULL) {
432 SYSERROR("Out of memory");
433 fclose(f);
434 return -1;
435 }
436 if (fread(buf, 1, flen, f) != flen) {
437 SYSERROR("Failure reading template");
438 free(buf);
439 fclose(f);
440 return -1;
441 }
442 if (fclose(f) < 0) {
443 SYSERROR("Failre closing template");
444 free(buf);
445 return -1;
446 }
447 buf[flen] = '\0';
448 ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, buf, flen, (void *)digest);
449 free(buf);
450 return ret;
451}
452#endif
61a1d519
CS
453
454char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
455{
456 va_list ap2;
457 size_t count = 1 + skip;
458 char **result;
459
460 /* first determine size of argument list, we don't want to reallocate
461 * constantly...
462 */
463 va_copy(ap2, ap);
464 while (1) {
465 char* arg = va_arg(ap2, char*);
466 if (!arg)
467 break;
468 count++;
469 }
470 va_end(ap2);
471
472 result = calloc(count, sizeof(char*));
473 if (!result)
474 return NULL;
475 count = skip;
476 while (1) {
477 char* arg = va_arg(ap, char*);
478 if (!arg)
479 break;
480 arg = do_strdup ? strdup(arg) : arg;
481 if (!arg)
482 goto oom;
483 result[count++] = arg;
484 }
485
486 /* calloc has already set last element to NULL*/
487 return result;
488
489oom:
490 free(result);
491 return NULL;
492}
493
494const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
495{
496 return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
497}