]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/machine-image.c
tree-wide: adjust fall through comments so that gcc is happy
[thirdparty/systemd.git] / src / shared / machine-image.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/file.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <linux/fs.h>
31
32 #include "alloc-util.h"
33 #include "btrfs-util.h"
34 #include "chattr-util.h"
35 #include "copy.h"
36 #include "dirent-util.h"
37 #include "env-util.h"
38 #include "fd-util.h"
39 #include "fs-util.h"
40 #include "hashmap.h"
41 #include "lockfile-util.h"
42 #include "log.h"
43 #include "machine-image.h"
44 #include "macro.h"
45 #include "mkdir.h"
46 #include "path-util.h"
47 #include "rm-rf.h"
48 #include "string-table.h"
49 #include "string-util.h"
50 #include "strv.h"
51 #include "time-util.h"
52 #include "utf8.h"
53 #include "util.h"
54 #include "xattr-util.h"
55
56 static const char image_search_path[] =
57 "/var/lib/machines\0"
58 "/var/lib/container\0" /* legacy */
59 "/usr/local/lib/machines\0"
60 "/usr/lib/machines\0";
61
62 Image *image_unref(Image *i) {
63 if (!i)
64 return NULL;
65
66 free(i->name);
67 free(i->path);
68 return mfree(i);
69 }
70
71 static char **image_settings_path(Image *image) {
72 _cleanup_strv_free_ char **l = NULL;
73 char **ret;
74 const char *fn, *s;
75 unsigned i = 0;
76
77 assert(image);
78
79 l = new0(char*, 4);
80 if (!l)
81 return NULL;
82
83 fn = strjoina(image->name, ".nspawn");
84
85 FOREACH_STRING(s, "/etc/systemd/nspawn/", "/run/systemd/nspawn/") {
86 l[i] = strappend(s, fn);
87 if (!l[i])
88 return NULL;
89
90 i++;
91 }
92
93 l[i] = file_in_same_dir(image->path, fn);
94 if (!l[i])
95 return NULL;
96
97 ret = l;
98 l = NULL;
99
100 return ret;
101 }
102
103 static char *image_roothash_path(Image *image) {
104 const char *fn;
105
106 assert(image);
107
108 fn = strjoina(image->name, ".roothash");
109
110 return file_in_same_dir(image->path, fn);
111 }
112
113 static int image_new(
114 ImageType t,
115 const char *pretty,
116 const char *path,
117 const char *filename,
118 bool read_only,
119 usec_t crtime,
120 usec_t mtime,
121 Image **ret) {
122
123 _cleanup_(image_unrefp) Image *i = NULL;
124
125 assert(t >= 0);
126 assert(t < _IMAGE_TYPE_MAX);
127 assert(pretty);
128 assert(filename);
129 assert(ret);
130
131 i = new0(Image, 1);
132 if (!i)
133 return -ENOMEM;
134
135 i->type = t;
136 i->read_only = read_only;
137 i->crtime = crtime;
138 i->mtime = mtime;
139 i->usage = i->usage_exclusive = (uint64_t) -1;
140 i->limit = i->limit_exclusive = (uint64_t) -1;
141
142 i->name = strdup(pretty);
143 if (!i->name)
144 return -ENOMEM;
145
146 if (path)
147 i->path = strjoin(path, "/", filename);
148 else
149 i->path = strdup(filename);
150
151 if (!i->path)
152 return -ENOMEM;
153
154 path_kill_slashes(i->path);
155
156 *ret = i;
157 i = NULL;
158
159 return 0;
160 }
161
162 static int image_make(
163 const char *pretty,
164 int dfd,
165 const char *path,
166 const char *filename,
167 Image **ret) {
168
169 struct stat st;
170 bool read_only;
171 int r;
172
173 assert(filename);
174
175 /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block
176 * devices into /var/lib/machines/, and treat them normally. */
177
178 if (fstatat(dfd, filename, &st, 0) < 0)
179 return -errno;
180
181 read_only =
182 (path && path_startswith(path, "/usr")) ||
183 (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
184
185 if (S_ISDIR(st.st_mode)) {
186 _cleanup_close_ int fd = -1;
187 unsigned file_attr = 0;
188
189 if (!ret)
190 return 1;
191
192 if (!pretty)
193 pretty = filename;
194
195 fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
196 if (fd < 0)
197 return -errno;
198
199 /* btrfs subvolumes have inode 256 */
200 if (st.st_ino == 256) {
201
202 r = btrfs_is_filesystem(fd);
203 if (r < 0)
204 return r;
205 if (r) {
206 BtrfsSubvolInfo info;
207
208 /* It's a btrfs subvolume */
209
210 r = btrfs_subvol_get_info_fd(fd, 0, &info);
211 if (r < 0)
212 return r;
213
214 r = image_new(IMAGE_SUBVOLUME,
215 pretty,
216 path,
217 filename,
218 info.read_only || read_only,
219 info.otime,
220 0,
221 ret);
222 if (r < 0)
223 return r;
224
225 if (btrfs_quota_scan_ongoing(fd) == 0) {
226 BtrfsQuotaInfo quota;
227
228 r = btrfs_subvol_get_subtree_quota_fd(fd, 0, &quota);
229 if (r >= 0) {
230 (*ret)->usage = quota.referenced;
231 (*ret)->usage_exclusive = quota.exclusive;
232
233 (*ret)->limit = quota.referenced_max;
234 (*ret)->limit_exclusive = quota.exclusive_max;
235 }
236 }
237
238 return 1;
239 }
240 }
241
242 /* If the IMMUTABLE bit is set, we consider the
243 * directory read-only. Since the ioctl is not
244 * supported everywhere we ignore failures. */
245 (void) read_attr_fd(fd, &file_attr);
246
247 /* It's just a normal directory. */
248 r = image_new(IMAGE_DIRECTORY,
249 pretty,
250 path,
251 filename,
252 read_only || (file_attr & FS_IMMUTABLE_FL),
253 0,
254 0,
255 ret);
256 if (r < 0)
257 return r;
258
259 return 1;
260
261 } else if (S_ISREG(st.st_mode) && endswith(filename, ".raw")) {
262 usec_t crtime = 0;
263
264 /* It's a RAW disk image */
265
266 if (!ret)
267 return 1;
268
269 fd_getcrtime_at(dfd, filename, &crtime, 0);
270
271 if (!pretty)
272 pretty = strndupa(filename, strlen(filename) - 4);
273
274 r = image_new(IMAGE_RAW,
275 pretty,
276 path,
277 filename,
278 !(st.st_mode & 0222) || read_only,
279 crtime,
280 timespec_load(&st.st_mtim),
281 ret);
282 if (r < 0)
283 return r;
284
285 (*ret)->usage = (*ret)->usage_exclusive = st.st_blocks * 512;
286 (*ret)->limit = (*ret)->limit_exclusive = st.st_size;
287
288 return 1;
289
290 } else if (S_ISBLK(st.st_mode)) {
291 _cleanup_close_ int block_fd = -1;
292 uint64_t size = UINT64_MAX;
293
294 /* A block device */
295
296 if (!ret)
297 return 1;
298
299 if (!pretty)
300 pretty = filename;
301
302 block_fd = openat(dfd, filename, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
303 if (block_fd < 0)
304 log_debug_errno(errno, "Failed to open block device %s/%s, ignoring: %m", path, filename);
305 else {
306 if (fstat(block_fd, &st) < 0)
307 return -errno;
308 if (!S_ISBLK(st.st_mode)) /* Verify that what we opened is actually what we think it is */
309 return -ENOTTY;
310
311 if (!read_only) {
312 int state = 0;
313
314 if (ioctl(block_fd, BLKROGET, &state) < 0)
315 log_debug_errno(errno, "Failed to issue BLKROGET on device %s/%s, ignoring: %m", path, filename);
316 else if (state)
317 read_only = true;
318 }
319
320 if (ioctl(block_fd, BLKGETSIZE64, &size) < 0)
321 log_debug_errno(errno, "Failed to issue BLKFLSBUF on device %s/%s, ignoring: %m", path, filename);
322
323 block_fd = safe_close(block_fd);
324 }
325
326 r = image_new(IMAGE_BLOCK,
327 pretty,
328 path,
329 filename,
330 !(st.st_mode & 0222) || read_only,
331 0,
332 0,
333 ret);
334 if (r < 0)
335 return r;
336
337 if (size != 0 && size != UINT64_MAX)
338 (*ret)->usage = (*ret)->usage_exclusive = (*ret)->limit = (*ret)->limit_exclusive = size;
339
340 return 1;
341 }
342
343 return 0;
344 }
345
346 int image_find(const char *name, Image **ret) {
347 const char *path;
348 int r;
349
350 assert(name);
351
352 /* There are no images with invalid names */
353 if (!image_name_is_valid(name))
354 return 0;
355
356 NULSTR_FOREACH(path, image_search_path) {
357 _cleanup_closedir_ DIR *d = NULL;
358
359 d = opendir(path);
360 if (!d) {
361 if (errno == ENOENT)
362 continue;
363
364 return -errno;
365 }
366
367 r = image_make(NULL, dirfd(d), path, name, ret);
368 if (IN_SET(r, 0, -ENOENT)) {
369 _cleanup_free_ char *raw = NULL;
370
371 raw = strappend(name, ".raw");
372 if (!raw)
373 return -ENOMEM;
374
375 r = image_make(NULL, dirfd(d), path, raw, ret);
376 if (IN_SET(r, 0, -ENOENT))
377 continue;
378 }
379 if (r < 0)
380 return r;
381
382 return 1;
383 }
384
385 if (streq(name, ".host"))
386 return image_make(".host", AT_FDCWD, NULL, "/", ret);
387
388 return 0;
389 };
390
391 int image_discover(Hashmap *h) {
392 const char *path;
393 int r;
394
395 assert(h);
396
397 NULSTR_FOREACH(path, image_search_path) {
398 _cleanup_closedir_ DIR *d = NULL;
399 struct dirent *de;
400
401 d = opendir(path);
402 if (!d) {
403 if (errno == ENOENT)
404 continue;
405
406 return -errno;
407 }
408
409 FOREACH_DIRENT_ALL(de, d, return -errno) {
410 _cleanup_(image_unrefp) Image *image = NULL;
411
412 if (!image_name_is_valid(de->d_name))
413 continue;
414
415 if (hashmap_contains(h, de->d_name))
416 continue;
417
418 r = image_make(NULL, dirfd(d), path, de->d_name, &image);
419 if (IN_SET(r, 0, -ENOENT))
420 continue;
421 if (r < 0)
422 return r;
423
424 r = hashmap_put(h, image->name, image);
425 if (r < 0)
426 return r;
427
428 image = NULL;
429 }
430 }
431
432 if (!hashmap_contains(h, ".host")) {
433 _cleanup_(image_unrefp) Image *image = NULL;
434
435 r = image_make(".host", AT_FDCWD, NULL, "/", &image);
436 if (r < 0)
437 return r;
438
439 r = hashmap_put(h, image->name, image);
440 if (r < 0)
441 return r;
442
443 image = NULL;
444
445 }
446
447 return 0;
448 }
449
450 void image_hashmap_free(Hashmap *map) {
451 Image *i;
452
453 while ((i = hashmap_steal_first(map)))
454 image_unref(i);
455
456 hashmap_free(map);
457 }
458
459 int image_remove(Image *i) {
460 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
461 _cleanup_strv_free_ char **settings = NULL;
462 _cleanup_free_ char *roothash = NULL;
463 char **j;
464 int r;
465
466 assert(i);
467
468 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
469 return -EROFS;
470
471 settings = image_settings_path(i);
472 if (!settings)
473 return -ENOMEM;
474
475 roothash = image_roothash_path(i);
476 if (!roothash)
477 return -ENOMEM;
478
479 /* Make sure we don't interfere with a running nspawn */
480 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
481 if (r < 0)
482 return r;
483
484 switch (i->type) {
485
486 case IMAGE_SUBVOLUME:
487
488 /* Let's unlink first, maybe it is a symlink? If that works we are happy. Otherwise, let's get out the
489 * big guns */
490 if (unlink(i->path) < 0) {
491 r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
492 if (r < 0)
493 return r;
494 }
495
496 break;
497
498 case IMAGE_DIRECTORY:
499 /* Allow deletion of read-only directories */
500 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
501 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
502 if (r < 0)
503 return r;
504
505 break;
506
507 case IMAGE_BLOCK:
508
509 /* If this is inside of /dev, then it's a real block device, hence let's not touch the device node
510 * itself (but let's remove the stuff stored alongside it). If it's anywhere else, let's try to unlink
511 * the thing (it's most likely a symlink after all). */
512
513 if (path_startswith(i->path, "/dev"))
514 break;
515
516 _fallthrough_;
517 case IMAGE_RAW:
518 if (unlink(i->path) < 0)
519 return -errno;
520 break;
521
522 default:
523 return -EOPNOTSUPP;
524 }
525
526 STRV_FOREACH(j, settings) {
527 if (unlink(*j) < 0 && errno != ENOENT)
528 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
529 }
530
531 if (unlink(roothash) < 0 && errno != ENOENT)
532 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash);
533
534 return 0;
535 }
536
537 static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
538 _cleanup_free_ char *rs = NULL;
539 const char *fn;
540
541 fn = strjoina(new_name, suffix);
542
543 rs = file_in_same_dir(path, fn);
544 if (!rs)
545 return -ENOMEM;
546
547 return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
548 }
549
550 int image_rename(Image *i, const char *new_name) {
551 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
552 _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
553 _cleanup_strv_free_ char **settings = NULL;
554 unsigned file_attr = 0;
555 char **j;
556 int r;
557
558 assert(i);
559
560 if (!image_name_is_valid(new_name))
561 return -EINVAL;
562
563 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
564 return -EROFS;
565
566 settings = image_settings_path(i);
567 if (!settings)
568 return -ENOMEM;
569
570 roothash = image_roothash_path(i);
571 if (!roothash)
572 return -ENOMEM;
573
574 /* Make sure we don't interfere with a running nspawn */
575 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
576 if (r < 0)
577 return r;
578
579 /* Make sure nobody takes the new name, between the time we
580 * checked it is currently unused in all search paths, and the
581 * time we take possession of it */
582 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
583 if (r < 0)
584 return r;
585
586 r = image_find(new_name, NULL);
587 if (r < 0)
588 return r;
589 if (r > 0)
590 return -EEXIST;
591
592 switch (i->type) {
593
594 case IMAGE_DIRECTORY:
595 /* Turn of the immutable bit while we rename the image, so that we can rename it */
596 (void) read_attr_path(i->path, &file_attr);
597
598 if (file_attr & FS_IMMUTABLE_FL)
599 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
600
601 _fallthrough_;
602 case IMAGE_SUBVOLUME:
603 new_path = file_in_same_dir(i->path, new_name);
604 break;
605
606 case IMAGE_BLOCK:
607
608 /* Refuse renaming raw block devices in /dev, the names are picked by udev after all. */
609 if (path_startswith(i->path, "/dev"))
610 return -EROFS;
611
612 new_path = file_in_same_dir(i->path, new_name);
613 break;
614
615 case IMAGE_RAW: {
616 const char *fn;
617
618 fn = strjoina(new_name, ".raw");
619 new_path = file_in_same_dir(i->path, fn);
620 break;
621 }
622
623 default:
624 return -EOPNOTSUPP;
625 }
626
627 if (!new_path)
628 return -ENOMEM;
629
630 nn = strdup(new_name);
631 if (!nn)
632 return -ENOMEM;
633
634 r = rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path);
635 if (r < 0)
636 return r;
637
638 /* Restore the immutable bit, if it was set before */
639 if (file_attr & FS_IMMUTABLE_FL)
640 (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
641
642 free(i->path);
643 i->path = new_path;
644 new_path = NULL;
645
646 free(i->name);
647 i->name = nn;
648 nn = NULL;
649
650 STRV_FOREACH(j, settings) {
651 r = rename_auxiliary_file(*j, new_name, ".nspawn");
652 if (r < 0 && r != -ENOENT)
653 log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
654 }
655
656 r = rename_auxiliary_file(roothash, new_name, ".roothash");
657 if (r < 0 && r != -ENOENT)
658 log_debug_errno(r, "Failed to rename roothash file %s, ignoring: %m", roothash);
659
660 return 0;
661 }
662
663 static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
664 _cleanup_free_ char *rs = NULL;
665 const char *fn;
666
667 fn = strjoina(new_name, suffix);
668
669 rs = file_in_same_dir(path, fn);
670 if (!rs)
671 return -ENOMEM;
672
673 return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK);
674 }
675
676 int image_clone(Image *i, const char *new_name, bool read_only) {
677 _cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT;
678 _cleanup_strv_free_ char **settings = NULL;
679 _cleanup_free_ char *roothash = NULL;
680 const char *new_path;
681 char **j;
682 int r;
683
684 assert(i);
685
686 if (!image_name_is_valid(new_name))
687 return -EINVAL;
688
689 settings = image_settings_path(i);
690 if (!settings)
691 return -ENOMEM;
692
693 roothash = image_roothash_path(i);
694 if (!roothash)
695 return -ENOMEM;
696
697 /* Make sure nobody takes the new name, between the time we
698 * checked it is currently unused in all search paths, and the
699 * time we take possession of it */
700 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
701 if (r < 0)
702 return r;
703
704 r = image_find(new_name, NULL);
705 if (r < 0)
706 return r;
707 if (r > 0)
708 return -EEXIST;
709
710 switch (i->type) {
711
712 case IMAGE_SUBVOLUME:
713 case IMAGE_DIRECTORY:
714 /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
715 * directory. */
716
717 new_path = strjoina("/var/lib/machines/", new_name);
718
719 r = btrfs_subvol_snapshot(i->path, new_path,
720 (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
721 BTRFS_SNAPSHOT_FALLBACK_COPY |
722 BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
723 BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
724 BTRFS_SNAPSHOT_RECURSIVE |
725 BTRFS_SNAPSHOT_QUOTA);
726 if (r >= 0)
727 /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
728 (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
729
730 break;
731
732 case IMAGE_RAW:
733 new_path = strjoina("/var/lib/machines/", new_name, ".raw");
734
735 r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
736 break;
737
738 case IMAGE_BLOCK:
739 default:
740 return -EOPNOTSUPP;
741 }
742
743 if (r < 0)
744 return r;
745
746 STRV_FOREACH(j, settings) {
747 r = clone_auxiliary_file(*j, new_name, ".nspawn");
748 if (r < 0 && r != -ENOENT)
749 log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
750 }
751
752 r = clone_auxiliary_file(roothash, new_name, ".roothash");
753 if (r < 0 && r != -ENOENT)
754 log_debug_errno(r, "Failed to clone root hash file %s, ignoring: %m", roothash);
755
756 return 0;
757 }
758
759 int image_read_only(Image *i, bool b) {
760 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
761 int r;
762 assert(i);
763
764 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
765 return -EROFS;
766
767 /* Make sure we don't interfere with a running nspawn */
768 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
769 if (r < 0)
770 return r;
771
772 switch (i->type) {
773
774 case IMAGE_SUBVOLUME:
775
776 /* Note that we set the flag only on the top-level
777 * subvolume of the image. */
778
779 r = btrfs_subvol_set_read_only(i->path, b);
780 if (r < 0)
781 return r;
782
783 break;
784
785 case IMAGE_DIRECTORY:
786 /* For simple directory trees we cannot use the access
787 mode of the top-level directory, since it has an
788 effect on the container itself. However, we can
789 use the "immutable" flag, to at least make the
790 top-level directory read-only. It's not as good as
791 a read-only subvolume, but at least something, and
792 we can read the value back. */
793
794 r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
795 if (r < 0)
796 return r;
797
798 break;
799
800 case IMAGE_RAW: {
801 struct stat st;
802
803 if (stat(i->path, &st) < 0)
804 return -errno;
805
806 if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0)
807 return -errno;
808
809 /* If the images is now read-only, it's a good time to
810 * defrag it, given that no write patterns will
811 * fragment it again. */
812 if (b)
813 (void) btrfs_defrag(i->path);
814 break;
815 }
816
817 case IMAGE_BLOCK: {
818 _cleanup_close_ int fd = -1;
819 struct stat st;
820 int state = b;
821
822 fd = open(i->path, O_CLOEXEC|O_RDONLY|O_NONBLOCK|O_NOCTTY);
823 if (fd < 0)
824 return -errno;
825
826 if (fstat(fd, &st) < 0)
827 return -errno;
828 if (!S_ISBLK(st.st_mode))
829 return -ENOTTY;
830
831 if (ioctl(fd, BLKROSET, &state) < 0)
832 return -errno;
833
834 break;
835 }
836
837 default:
838 return -EOPNOTSUPP;
839 }
840
841 return 0;
842 }
843
844 int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local) {
845 _cleanup_free_ char *p = NULL;
846 LockFile t = LOCK_FILE_INIT;
847 struct stat st;
848 int r;
849
850 assert(path);
851 assert(global);
852 assert(local);
853
854 /* Locks an image path. This actually creates two locks: one
855 * "local" one, next to the image path itself, which might be
856 * shared via NFS. And another "global" one, in /run, that
857 * uses the device/inode number. This has the benefit that we
858 * can even lock a tree that is a mount point, correctly. */
859
860 if (!path_is_absolute(path))
861 return -EINVAL;
862
863 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
864 *local = *global = (LockFile) LOCK_FILE_INIT;
865 return 0;
866 }
867
868 if (path_equal(path, "/"))
869 return -EBUSY;
870
871 if (stat(path, &st) >= 0) {
872 if (S_ISBLK(st.st_mode))
873 r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev));
874 else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))
875 r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino);
876 else
877 return -ENOTTY;
878
879 if (r < 0)
880 return -ENOMEM;
881 }
882
883 /* For block devices we don't need the "local" lock, as the major/minor lock above should be sufficient, since
884 * block devices are device local anyway. */
885 if (!path_startswith(path, "/dev")) {
886 r = make_lock_file_for(path, operation, &t);
887 if (r < 0)
888 return r;
889 }
890
891 if (p) {
892 mkdir_p("/run/systemd/nspawn/locks", 0700);
893
894 r = make_lock_file(p, operation, global);
895 if (r < 0) {
896 release_lock_file(&t);
897 return r;
898 }
899 } else
900 *global = (LockFile) LOCK_FILE_INIT;
901
902 *local = t;
903 return 0;
904 }
905
906 int image_set_limit(Image *i, uint64_t referenced_max) {
907 assert(i);
908
909 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
910 return -EROFS;
911
912 if (i->type != IMAGE_SUBVOLUME)
913 return -EOPNOTSUPP;
914
915 /* We set the quota both for the subvolume as well as for the
916 * subtree. The latter is mostly for historical reasons, since
917 * we didn't use to have a concept of subtree quota, and hence
918 * only modified the subvolume quota. */
919
920 (void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
921 (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
922 return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
923 }
924
925 int image_name_lock(const char *name, int operation, LockFile *ret) {
926 const char *p;
927
928 assert(name);
929 assert(ret);
930
931 /* Locks an image name, regardless of the precise path used. */
932
933 if (!image_name_is_valid(name))
934 return -EINVAL;
935
936 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
937 *ret = (LockFile) LOCK_FILE_INIT;
938 return 0;
939 }
940
941 if (streq(name, ".host"))
942 return -EBUSY;
943
944 mkdir_p("/run/systemd/nspawn/locks", 0700);
945 p = strjoina("/run/systemd/nspawn/locks/name-", name);
946
947 return make_lock_file(p, operation, ret);
948 }
949
950 bool image_name_is_valid(const char *s) {
951 if (!filename_is_valid(s))
952 return false;
953
954 if (string_has_cc(s, NULL))
955 return false;
956
957 if (!utf8_is_valid(s))
958 return false;
959
960 /* Temporary files for atomically creating new files */
961 if (startswith(s, ".#"))
962 return false;
963
964 return true;
965 }
966
967 static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
968 [IMAGE_DIRECTORY] = "directory",
969 [IMAGE_SUBVOLUME] = "subvolume",
970 [IMAGE_RAW] = "raw",
971 [IMAGE_BLOCK] = "block",
972 };
973
974 DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);