]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/storage_utils.c
storage_utils: add error handling
[mirror_lxc.git] / src / lxc / storage / storage_utils.c
1 /*
2 * lxc: linux Container library
3 *
4 * Copyright © 2017 Canonical Ltd.
5 *
6 * Authors:
7 * Christian Brauner <christian.brauner@ubuntu.com>
8 *
9 * This program 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 program 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 program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE 1
26 #endif
27 #include <ctype.h>
28 #include <dirent.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <grp.h>
32 #include <inttypes.h>
33 #include <libgen.h>
34 #include <sched.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/mount.h>
39 #include <sys/prctl.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <unistd.h>
44
45 #include "config.h"
46 #include "log.h"
47 #include "nbd.h"
48 #include "parse.h"
49 #include "storage.h"
50 #include "storage_utils.h"
51 #include "syscall_wrappers.h"
52 #include "utils.h"
53
54 #ifndef HAVE_STRLCPY
55 #include "include/strlcpy.h"
56 #endif
57
58 #ifndef BLKGETSIZE64
59 #define BLKGETSIZE64 _IOR(0x12, 114, size_t)
60 #endif
61
62 lxc_log_define(storage_utils, lxc);
63
64 /* the bulk of this needs to become a common helper */
65 char *dir_new_path(char *src, const char *oldname, const char *name,
66 const char *oldpath, const char *lxcpath)
67 {
68 char *ret, *p, *p2;
69 int l1, l2, nlen;
70
71 nlen = strlen(src) + 1;
72 l1 = strlen(oldpath);
73 p = src;
74 /* if src starts with oldpath, look for oldname only after
75 * that path */
76 if (strncmp(src, oldpath, l1) == 0) {
77 p += l1;
78 nlen += (strlen(lxcpath) - l1);
79 }
80 l2 = strlen(oldname);
81 while ((p = strstr(p, oldname)) != NULL) {
82 p += l2;
83 nlen += strlen(name) - l2;
84 }
85
86 ret = malloc(nlen);
87 if (!ret)
88 return NULL;
89
90 p = ret;
91 if (strncmp(src, oldpath, l1) == 0) {
92 p += sprintf(p, "%s", lxcpath);
93 src += l1;
94 }
95
96 while ((p2 = strstr(src, oldname)) != NULL) {
97 size_t retlen;
98
99 /* copy text up to oldname */
100 retlen = strlcpy(p, src, p2 - src);
101 if (retlen >= p2 - src) {
102 free(ret);
103 return NULL;
104 }
105
106 /* move target pointer (p) */
107 p += p2 - src;
108 /* print new name in place of oldname */
109 p += sprintf(p, "%s", name);
110 /* move src to end of oldname */
111 src = p2 + l2;
112 }
113
114 /* copy the rest of src */
115 sprintf(p, "%s", src);
116 return ret;
117 }
118
119 /*
120 * attach_block_device returns true if all went well,
121 * meaning either a block device was attached or was not
122 * needed. It returns false if something went wrong and
123 * container startup should be stopped.
124 */
125 bool attach_block_device(struct lxc_conf *conf)
126 {
127 char *path;
128
129 if (!conf->rootfs.path)
130 return true;
131
132 path = conf->rootfs.path;
133 if (!requires_nbd(path))
134 return true;
135
136 path = strchr(path, ':');
137 if (!path)
138 return false;
139
140 path++;
141 if (!attach_nbd(path, conf))
142 return false;
143
144 return true;
145 }
146
147 /*
148 * return block size of dev->src in units of bytes
149 */
150 int blk_getsize(struct lxc_storage *bdev, uint64_t *size)
151 {
152 int fd, ret;
153 const char *src;
154
155 src = lxc_storage_get_path(bdev->src, bdev->type);
156
157 fd = open(src, O_RDONLY | O_CLOEXEC);
158 if (fd < 0) {
159 SYSERROR("Failed to open \"%s\"", src);
160 return -1;
161 }
162
163 /* size of device in bytes */
164 ret = ioctl(fd, BLKGETSIZE64, size);
165 if (ret < 0)
166 SYSERROR("Failed to get block size of dev-src");
167
168 close(fd);
169 return ret;
170 }
171
172 void detach_block_device(struct lxc_conf *conf)
173 {
174 if (conf->nbd_idx != -1)
175 detach_nbd_idx(conf->nbd_idx);
176 }
177
178 /*
179 * Given a lxc_storage (presumably blockdev-based), detect the fstype
180 * by trying mounting (in a private mntns) it.
181 * @lxc_storage: bdev to investigate
182 * @type: preallocated char* in which to write the fstype
183 * @len: length of passed in char*
184 * Returns length of fstype, of -1 on error
185 */
186 int detect_fs(struct lxc_storage *bdev, char *type, int len)
187 {
188 int ret;
189 int p[2];
190 size_t linelen;
191 pid_t pid;
192 FILE *f;
193 char *sp1, *sp2, *sp3;
194 const char *l, *srcdev;
195 char devpath[PATH_MAX];
196 char *line = NULL;
197
198 if (!bdev || !bdev->src || !bdev->dest)
199 return -1;
200
201 srcdev = lxc_storage_get_path(bdev->src, bdev->type);
202
203 ret = pipe(p);
204 if (ret < 0) {
205 SYSERROR("Failed to create pipe");
206 return -1;
207 }
208
209 pid = fork();
210 if (pid < 0) {
211 SYSERROR("Failed to fork process");
212 return -1;
213 }
214
215 if (pid > 0) {
216 int status;
217 close(p[1]);
218 memset(type, 0, len);
219 ret = read(p[0], type, len - 1);
220 close(p[0]);
221 if (ret < 0) {
222 SYSERROR("error reading from pipe");
223 wait(&status);
224 return -1;
225 } else if (ret == 0) {
226 ERROR("child exited early - fstype not found");
227 wait(&status);
228 return -1;
229 }
230 wait(&status);
231 type[len - 1] = '\0';
232 INFO("detected fstype %s for %s", type, srcdev);
233 return ret;
234 }
235
236 if (unshare(CLONE_NEWNS) < 0)
237 exit(1);
238
239 if (detect_shared_rootfs()) {
240 if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) {
241 SYSERROR("Failed to make / rslave");
242 ERROR("Continuing...");
243 }
244 }
245
246 ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
247 if (ret < 0) {
248 ERROR("failed mounting %s onto %s to detect fstype", srcdev,
249 bdev->dest);
250 exit(1);
251 }
252
253 l = linkderef(srcdev, devpath);
254 if (!l)
255 exit(1);
256 f = fopen("/proc/self/mounts", "r");
257 if (!f)
258 exit(1);
259
260 while (getline(&line, &linelen, f) != -1) {
261 sp1 = strchr(line, ' ');
262 if (!sp1)
263 exit(1);
264 *sp1 = '\0';
265 if (strcmp(line, l))
266 continue;
267 sp2 = strchr(sp1 + 1, ' ');
268 if (!sp2)
269 exit(1);
270 *sp2 = '\0';
271 sp3 = strchr(sp2 + 1, ' ');
272 if (!sp3)
273 exit(1);
274 *sp3 = '\0';
275 sp2++;
276 if (write(p[1], sp2, strlen(sp2)) != strlen(sp2))
277 exit(1);
278
279 exit(0);
280 }
281
282 exit(1);
283 }
284
285 int do_mkfs_exec_wrapper(void *args)
286 {
287 int ret;
288 char *mkfs;
289 char **data = args;
290 /* strlen("mkfs.")
291 * +
292 * strlen(data[0])
293 * +
294 * \0
295 */
296 size_t len = 5 + strlen(data[0]) + 1;
297
298 mkfs = malloc(len);
299 if (!mkfs)
300 return -1;
301
302 ret = snprintf(mkfs, len, "mkfs.%s", data[0]);
303 if (ret < 0 || (size_t)ret >= len) {
304 free(mkfs);
305 return -1;
306 }
307
308 TRACE("executing \"%s %s\"", mkfs, data[1]);
309 execlp(mkfs, mkfs, data[1], (char *)NULL);
310 SYSERROR("failed to run \"%s %s \"", mkfs, data[1]);
311 free(mkfs);
312 return -1;
313 }
314
315 /*
316 * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm
317 * is a block device.
318 */
319 int is_blktype(struct lxc_storage *b)
320 {
321 if (strcmp(b->type, "lvm") == 0)
322 return 1;
323
324 return 0;
325 }
326
327 int mount_unknown_fs(const char *rootfs, const char *target,
328 const char *options)
329 {
330 size_t i;
331 int ret;
332 struct cbarg {
333 const char *rootfs;
334 const char *target;
335 const char *options;
336 } cbarg = {
337 .rootfs = rootfs,
338 .target = target,
339 .options = options,
340 };
341
342 /*
343 * find the filesystem type with brute force:
344 * first we check with /etc/filesystems, in case the modules
345 * are auto-loaded and fall back to the supported kernel fs
346 */
347 char *fsfile[] = {
348 "/etc/filesystems",
349 "/proc/filesystems",
350 };
351
352 for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) {
353 if (access(fsfile[i], F_OK))
354 continue;
355
356 ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
357 if (ret < 0) {
358 ERROR("failed to parse '%s'", fsfile[i]);
359 return -1;
360 }
361
362 if (ret)
363 return 0;
364 }
365
366 ERROR("failed to determine fs type for '%s'", rootfs);
367 return -1;
368 }
369
370 /*
371 * These are copied from conf.c. However as conf.c will be moved to using
372 * the callback system, they can be pulled from there eventually, so we
373 * don't need to pollute utils.c with these low level functions
374 */
375 int find_fstype_cb(char *buffer, void *data)
376 {
377 struct cbarg {
378 const char *rootfs;
379 const char *target;
380 const char *options;
381 } *cbarg = data;
382
383 unsigned long mntflags;
384 char *mntdata;
385 char *fstype;
386
387 /* we don't try 'nodev' entries */
388 if (strstr(buffer, "nodev"))
389 return 0;
390
391 fstype = buffer;
392 fstype += lxc_char_left_gc(fstype, strlen(fstype));
393 fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
394
395 DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs,
396 cbarg->target, fstype);
397
398 if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
399 free(mntdata);
400 return 0;
401 }
402
403 if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) {
404 SYSDEBUG("mount failed with error");
405 free(mntdata);
406 return 0;
407 }
408
409 free(mntdata);
410
411 INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs,
412 cbarg->target, fstype);
413
414 return 1;
415 }
416
417 const char *linkderef(const char *path, char *dest)
418 {
419 struct stat sbuf;
420 ssize_t ret;
421
422 ret = stat(path, &sbuf);
423 if (ret < 0) {
424 SYSERROR("Failed to get status of file - \"%s\"", path);
425 return NULL;
426 }
427
428 if (!S_ISLNK(sbuf.st_mode))
429 return path;
430
431 ret = readlink(path, dest, PATH_MAX);
432 if (ret < 0) {
433 SYSERROR("error reading link %s", path);
434 return NULL;
435 } else if (ret >= PATH_MAX) {
436 ERROR("link in %s too long", path);
437 return NULL;
438 }
439 dest[ret] = '\0';
440
441 return dest;
442 }
443
444 /*
445 * is an unprivileged user allowed to make this kind of snapshot
446 */
447 bool unpriv_snap_allowed(struct lxc_storage *b, const char *t, bool snap,
448 bool maybesnap)
449 {
450 if (!t) {
451 /* New type will be same as original (unless snap && b->type ==
452 * dir, in which case it will be overlayfs -- which is also
453 * allowed).
454 */
455 if (strcmp(b->type, "dir") == 0 ||
456 strcmp(b->type, "overlay") == 0 ||
457 strcmp(b->type, "overlayfs") == 0 ||
458 strcmp(b->type, "btrfs") == 0 ||
459 strcmp(b->type, "loop") == 0)
460 return true;
461
462 return false;
463 }
464
465 /* Unprivileged users can copy and snapshot dir, overlayfs, and loop.
466 * In particular, not zfs, btrfs, or lvm.
467 */
468 if (strcmp(t, "dir") == 0 ||
469 strcmp(t, "overlay") == 0 ||
470 strcmp(t, "overlayfs") == 0 ||
471 strcmp(t, "btrfs") == 0 ||
472 strcmp(t, "loop") == 0)
473 return true;
474
475 return false;
476 }
477
478 uint64_t get_fssize(char *s)
479 {
480 uint64_t ret;
481 char *end;
482
483 ret = strtoull(s, &end, 0);
484 if (end == s) {
485 ERROR("Invalid blockdev size '%s', using default size", s);
486 return 0;
487 }
488
489 while (isblank(*end))
490 end++;
491
492 if (*end == '\0') {
493 ret *= 1024ULL * 1024ULL; /* MB by default */
494 } else if (*end == 'b' || *end == 'B') {
495 ret *= 1ULL;
496 } else if (*end == 'k' || *end == 'K') {
497 ret *= 1024ULL;
498 } else if (*end == 'm' || *end == 'M') {
499 ret *= 1024ULL * 1024ULL;
500 } else if (*end == 'g' || *end == 'G') {
501 ret *= 1024ULL * 1024ULL * 1024ULL;
502 } else if (*end == 't' || *end == 'T') {
503 ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
504 } else {
505 ERROR("Invalid blockdev unit size '%c' in '%s', using default size", *end, s);
506 return 0;
507 }
508
509 return ret;
510 }
511
512 bool is_valid_storage_type(const char *type)
513 {
514 if (strcmp(type, "dir") == 0 ||
515 strcmp(type, "btrfs") == 0 ||
516 strcmp(type, "loop") == 0 ||
517 strcmp(type, "lvm") == 0 ||
518 strcmp(type, "nbd") == 0 ||
519 strcmp(type, "overlay") == 0 ||
520 strcmp(type, "overlayfs") == 0 ||
521 strcmp(type, "rbd") == 0 ||
522 strcmp(type, "zfs") == 0)
523 return true;
524
525 return false;
526 }
527
528 int storage_destroy_wrapper(void *data)
529 {
530 struct lxc_conf *conf = data;
531
532 if (setgid(0) < 0) {
533 SYSERROR("Failed to setgid to 0");
534 return -1;
535 }
536
537 if (setgroups(0, NULL) < 0)
538 SYSWARN("Failed to clear groups");
539
540 if (setuid(0) < 0) {
541 SYSERROR("Failed to setuid to 0");
542 return -1;
543 }
544
545 if (!storage_destroy(conf)) {
546 ERROR("Failed to destroy storage");
547 return -1;
548 }
549
550 return 0;
551 }