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