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