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