]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/machine-image.c
bootspec: fix debug message about default entry
[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;
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
bafbac4e
LP
113static 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
c2ce6a3d 123static int image_new(
cd61c3bf 124 ImageType t,
5fc7f358 125 const char *pretty,
cd61c3bf 126 const char *path,
5fc7f358 127 const char *filename,
cd61c3bf 128 bool read_only,
10f9c755 129 usec_t crtime,
cd61c3bf 130 usec_t mtime,
c2ce6a3d 131 Image **ret) {
cd61c3bf
LP
132
133 _cleanup_(image_unrefp) Image *i = NULL;
cd61c3bf 134
cd61c3bf
LP
135 assert(t >= 0);
136 assert(t < _IMAGE_TYPE_MAX);
5fc7f358
LP
137 assert(pretty);
138 assert(filename);
c2ce6a3d 139 assert(ret);
cd61c3bf 140
c2ce6a3d 141 i = new0(Image, 1);
cd61c3bf
LP
142 if (!i)
143 return -ENOMEM;
144
145 i->type = t;
146 i->read_only = read_only;
10f9c755 147 i->crtime = crtime;
cd61c3bf 148 i->mtime = mtime;
c19de711 149 i->usage = i->usage_exclusive = (uint64_t) -1;
b6b18498 150 i->limit = i->limit_exclusive = (uint64_t) -1;
cd61c3bf 151
5fc7f358 152 i->name = strdup(pretty);
cd61c3bf
LP
153 if (!i->name)
154 return -ENOMEM;
155
5fc7f358 156 if (path)
605405c6 157 i->path = strjoin(path, "/", filename);
5fc7f358
LP
158 else
159 i->path = strdup(filename);
ebeccf9e 160
5fc7f358
LP
161 if (!i->path)
162 return -ENOMEM;
163
164 path_kill_slashes(i->path);
cd61c3bf 165
c2ce6a3d 166 *ret = i;
cd61c3bf 167 i = NULL;
c2ce6a3d 168
cd61c3bf
LP
169 return 0;
170}
171
5fc7f358
LP
172static int image_make(
173 const char *pretty,
174 int dfd,
175 const char *path,
176 const char *filename,
177 Image **ret) {
178
c2ce6a3d 179 struct stat st;
5fc7f358 180 bool read_only;
cd61c3bf
LP
181 int r;
182
5fc7f358 183 assert(filename);
cd61c3bf 184
eb38edce
LP
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. */
cd61c3bf 187
5fc7f358 188 if (fstatat(dfd, filename, &st, 0) < 0)
c2ce6a3d 189 return -errno;
cd61c3bf 190
5fc7f358
LP
191 read_only =
192 (path && path_startswith(path, "/usr")) ||
08ff5529 193 (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
86e339c8 194
c2ce6a3d 195 if (S_ISDIR(st.st_mode)) {
01b72568
LP
196 _cleanup_close_ int fd = -1;
197 unsigned file_attr = 0;
cd61c3bf 198
c2ce6a3d
LP
199 if (!ret)
200 return 1;
cd61c3bf 201
5fc7f358
LP
202 if (!pretty)
203 pretty = filename;
204
01b72568
LP
205 fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
206 if (fd < 0)
207 return -errno;
208
c2ce6a3d
LP
209 /* btrfs subvolumes have inode 256 */
210 if (st.st_ino == 256) {
cd61c3bf 211
21222ea5
LP
212 r = btrfs_is_filesystem(fd);
213 if (r < 0)
214 return r;
215 if (r) {
10f9c755 216 BtrfsSubvolInfo info;
cd61c3bf 217
c2ce6a3d 218 /* It's a btrfs subvolume */
cd61c3bf 219
5bcd08db 220 r = btrfs_subvol_get_info_fd(fd, 0, &info);
10f9c755
LP
221 if (r < 0)
222 return r;
c2ce6a3d
LP
223
224 r = image_new(IMAGE_SUBVOLUME,
5fc7f358 225 pretty,
c2ce6a3d 226 path,
5fc7f358
LP
227 filename,
228 info.read_only || read_only,
10f9c755 229 info.otime,
c2ce6a3d 230 0,
c2ce6a3d
LP
231 ret);
232 if (r < 0)
233 return r;
234
5bcd08db
LP
235 if (btrfs_quota_scan_ongoing(fd) == 0) {
236 BtrfsQuotaInfo quota;
b6b18498 237
5bcd08db
LP
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 }
b6b18498
LP
246 }
247
c2ce6a3d 248 return 1;
cd61c3bf 249 }
c2ce6a3d 250 }
cd61c3bf 251
01b72568
LP
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);
cd61c3bf 256
01b72568 257 /* It's just a normal directory. */
c2ce6a3d 258 r = image_new(IMAGE_DIRECTORY,
5fc7f358 259 pretty,
c2ce6a3d 260 path,
5fc7f358 261 filename,
01b72568 262 read_only || (file_attr & FS_IMMUTABLE_FL),
c2ce6a3d
LP
263 0,
264 0,
265 ret);
266 if (r < 0)
267 return r;
cd61c3bf 268
c2ce6a3d 269 return 1;
cd61c3bf 270
aceac2f0 271 } else if (S_ISREG(st.st_mode) && endswith(filename, ".raw")) {
10f9c755 272 usec_t crtime = 0;
cd61c3bf 273
aceac2f0 274 /* It's a RAW disk image */
cd61c3bf 275
c2ce6a3d
LP
276 if (!ret)
277 return 1;
cd61c3bf 278
5fc7f358 279 fd_getcrtime_at(dfd, filename, &crtime, 0);
10f9c755 280
5fc7f358
LP
281 if (!pretty)
282 pretty = strndupa(filename, strlen(filename) - 4);
10f9c755 283
aceac2f0 284 r = image_new(IMAGE_RAW,
5fc7f358 285 pretty,
c2ce6a3d 286 path,
5fc7f358
LP
287 filename,
288 !(st.st_mode & 0222) || read_only,
10f9c755 289 crtime,
c2ce6a3d 290 timespec_load(&st.st_mtim),
c2ce6a3d
LP
291 ret);
292 if (r < 0)
293 return r;
cd61c3bf 294
c19de711 295 (*ret)->usage = (*ret)->usage_exclusive = st.st_blocks * 512;
b6b18498
LP
296 (*ret)->limit = (*ret)->limit_exclusive = st.st_size;
297
c2ce6a3d 298 return 1;
eb38edce
LP
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;
c2ce6a3d 351 }
cd61c3bf 352
c2ce6a3d
LP
353 return 0;
354}
cd61c3bf 355
c2ce6a3d
LP
356int image_find(const char *name, Image **ret) {
357 const char *path;
358 int r;
cd61c3bf 359
c2ce6a3d 360 assert(name);
cd61c3bf 361
c2ce6a3d
LP
362 /* There are no images with invalid names */
363 if (!image_name_is_valid(name))
364 return 0;
cd61c3bf 365
c2ce6a3d
LP
366 NULSTR_FOREACH(path, image_search_path) {
367 _cleanup_closedir_ DIR *d = NULL;
cd61c3bf 368
c2ce6a3d
LP
369 d = opendir(path);
370 if (!d) {
371 if (errno == ENOENT)
372 continue;
cd61c3bf 373
c2ce6a3d
LP
374 return -errno;
375 }
cd61c3bf 376
5fc7f358 377 r = image_make(NULL, dirfd(d), path, name, ret);
4c701096 378 if (IN_SET(r, 0, -ENOENT)) {
aceac2f0 379 _cleanup_free_ char *raw = NULL;
5fc7f358 380
aceac2f0
LP
381 raw = strappend(name, ".raw");
382 if (!raw)
5fc7f358
LP
383 return -ENOMEM;
384
aceac2f0 385 r = image_make(NULL, dirfd(d), path, raw, ret);
4c701096 386 if (IN_SET(r, 0, -ENOENT))
5fc7f358
LP
387 continue;
388 }
c2ce6a3d
LP
389 if (r < 0)
390 return r;
cd61c3bf 391
c2ce6a3d
LP
392 return 1;
393 }
394
5fc7f358 395 if (streq(name, ".host"))
27c88c4e 396 return image_make(".host", AT_FDCWD, NULL, "/", ret);
5fc7f358 397
c2ce6a3d
LP
398 return 0;
399};
400
401int 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)
a67a4c8c 414 continue;
c2ce6a3d
LP
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
5fc7f358 428 r = image_make(NULL, dirfd(d), path, de->d_name, &image);
4c701096 429 if (IN_SET(r, 0, -ENOENT))
c2ce6a3d
LP
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;
cd61c3bf
LP
439 }
440 }
441
5fc7f358
LP
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
cd61c3bf
LP
457 return 0;
458}
459
08682124 460int image_remove(Image *i) {
30535c16 461 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
8e0b6570 462 _cleanup_strv_free_ char **settings = NULL;
bafbac4e 463 _cleanup_free_ char *roothash = NULL;
8e0b6570 464 char **j;
30535c16
LP
465 int r;
466
08682124
LP
467 assert(i);
468
d94c2b06 469 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
08682124
LP
470 return -EROFS;
471
8e0b6570
LP
472 settings = image_settings_path(i);
473 if (!settings)
474 return -ENOMEM;
475
bafbac4e
LP
476 roothash = image_roothash_path(i);
477 if (!roothash)
478 return -ENOMEM;
479
30535c16
LP
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
ebd93cb6
LP
485 switch (i->type) {
486
487 case IMAGE_SUBVOLUME:
9fb0b9c7
LP
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
8e0b6570 497 break;
ebd93cb6
LP
498
499 case IMAGE_DIRECTORY:
01b72568 500 /* Allow deletion of read-only directories */
a67d68b8 501 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
8e0b6570
LP
502 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
503 if (r < 0)
504 return r;
505
506 break;
01b72568 507
eb38edce
LP
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
4831981d 517 _fallthrough_;
aceac2f0 518 case IMAGE_RAW:
41d1ed05
LP
519 if (unlink(i->path) < 0)
520 return -errno;
8e0b6570 521 break;
ebd93cb6
LP
522
523 default:
15411c0c 524 return -EOPNOTSUPP;
ebd93cb6 525 }
8e0b6570
LP
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
bafbac4e
LP
532 if (unlink(roothash) < 0 && errno != ENOENT)
533 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash);
534
8e0b6570
LP
535 return 0;
536}
537
bafbac4e 538static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
8e0b6570
LP
539 _cleanup_free_ char *rs = NULL;
540 const char *fn;
541
bafbac4e 542 fn = strjoina(new_name, suffix);
8e0b6570
LP
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);
ebd93cb6
LP
549}
550
551int image_rename(Image *i, const char *new_name) {
30535c16 552 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
bafbac4e 553 _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
8e0b6570 554 _cleanup_strv_free_ char **settings = NULL;
01b72568 555 unsigned file_attr = 0;
8e0b6570 556 char **j;
ebd93cb6
LP
557 int r;
558
559 assert(i);
560
561 if (!image_name_is_valid(new_name))
562 return -EINVAL;
563
d94c2b06 564 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
ebd93cb6
LP
565 return -EROFS;
566
8e0b6570
LP
567 settings = image_settings_path(i);
568 if (!settings)
569 return -ENOMEM;
570
bafbac4e
LP
571 roothash = image_roothash_path(i);
572 if (!roothash)
573 return -ENOMEM;
574
30535c16
LP
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
f8e2f4d6 582 * time we take possession of it */
30535c16
LP
583 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
584 if (r < 0)
585 return r;
586
ebd93cb6
LP
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
ebd93cb6 595 case IMAGE_DIRECTORY:
01b72568
LP
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)
a67d68b8 600 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
01b72568 601
4831981d 602 _fallthrough_;
01b72568 603 case IMAGE_SUBVOLUME:
ebd93cb6
LP
604 new_path = file_in_same_dir(i->path, new_name);
605 break;
606
eb38edce
LP
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
aceac2f0 616 case IMAGE_RAW: {
ebd93cb6
LP
617 const char *fn;
618
63c372cb 619 fn = strjoina(new_name, ".raw");
ebd93cb6
LP
620 new_path = file_in_same_dir(i->path, fn);
621 break;
622 }
623
624 default:
15411c0c 625 return -EOPNOTSUPP;
ebd93cb6
LP
626 }
627
628 if (!new_path)
629 return -ENOMEM;
630
631 nn = strdup(new_name);
632 if (!nn)
633 return -ENOMEM;
634
f85ef957
AC
635 r = rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path);
636 if (r < 0)
637 return r;
ebd93cb6 638
01b72568
LP
639 /* Restore the immutable bit, if it was set before */
640 if (file_attr & FS_IMMUTABLE_FL)
a67d68b8 641 (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
01b72568 642
f9ecfd3b
DL
643 free_and_replace(i->path, new_path);
644 free_and_replace(i->name, nn);
ebd93cb6 645
8e0b6570 646 STRV_FOREACH(j, settings) {
bafbac4e 647 r = rename_auxiliary_file(*j, new_name, ".nspawn");
8e0b6570
LP
648 if (r < 0 && r != -ENOENT)
649 log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
650 }
651
bafbac4e
LP
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
ebd93cb6
LP
656 return 0;
657}
658
bafbac4e 659static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
8e0b6570
LP
660 _cleanup_free_ char *rs = NULL;
661 const char *fn;
662
bafbac4e 663 fn = strjoina(new_name, suffix);
8e0b6570
LP
664
665 rs = file_in_same_dir(path, fn);
666 if (!rs)
667 return -ENOMEM;
668
1c876927 669 return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK);
8e0b6570
LP
670}
671
ebd93cb6 672int image_clone(Image *i, const char *new_name, bool read_only) {
30535c16 673 _cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT;
8e0b6570 674 _cleanup_strv_free_ char **settings = NULL;
bafbac4e 675 _cleanup_free_ char *roothash = NULL;
ebd93cb6 676 const char *new_path;
8e0b6570 677 char **j;
ebd93cb6
LP
678 int r;
679
680 assert(i);
681
682 if (!image_name_is_valid(new_name))
683 return -EINVAL;
684
8e0b6570
LP
685 settings = image_settings_path(i);
686 if (!settings)
687 return -ENOMEM;
688
bafbac4e
LP
689 roothash = image_roothash_path(i);
690 if (!roothash)
691 return -ENOMEM;
692
30535c16
LP
693 /* Make sure nobody takes the new name, between the time we
694 * checked it is currently unused in all search paths, and the
f8e2f4d6 695 * time we take possession of it */
30535c16
LP
696 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
697 if (r < 0)
698 return r;
699
ebd93cb6
LP
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:
9a50e3ca 710 /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
13e785f7 711 * directory. */
9a50e3ca 712
63c372cb 713 new_path = strjoina("/var/lib/machines/", new_name);
ebd93cb6 714
17cbb288
LP
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)
9a50e3ca 723 /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
8120ee28 724 (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
5bcd08db 725
ebd93cb6
LP
726 break;
727
aceac2f0 728 case IMAGE_RAW:
63c372cb 729 new_path = strjoina("/var/lib/machines/", new_name, ".raw");
ebd93cb6 730
1c876927 731 r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
ebd93cb6
LP
732 break;
733
eb38edce 734 case IMAGE_BLOCK:
ebd93cb6 735 default:
15411c0c 736 return -EOPNOTSUPP;
ebd93cb6
LP
737 }
738
739 if (r < 0)
740 return r;
741
8e0b6570 742 STRV_FOREACH(j, settings) {
bafbac4e 743 r = clone_auxiliary_file(*j, new_name, ".nspawn");
8e0b6570
LP
744 if (r < 0 && r != -ENOENT)
745 log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
746 }
747
bafbac4e
LP
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
ebd93cb6
LP
752 return 0;
753}
754
755int image_read_only(Image *i, bool b) {
30535c16 756 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
ebd93cb6 757 int r;
c7664c07 758
ebd93cb6
LP
759 assert(i);
760
d94c2b06 761 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
ebd93cb6
LP
762 return -EROFS;
763
30535c16
LP
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
ebd93cb6
LP
769 switch (i->type) {
770
771 case IMAGE_SUBVOLUME:
5bcd08db
LP
772
773 /* Note that we set the flag only on the top-level
774 * subvolume of the image. */
775
ebd93cb6
LP
776 r = btrfs_subvol_set_read_only(i->path, b);
777 if (r < 0)
778 return r;
01b72568
LP
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
13e785f7 789 we can read the value back. */
01b72568 790
a67d68b8 791 r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
01b72568
LP
792 if (r < 0)
793 return r;
794
ebd93cb6
LP
795 break;
796
aceac2f0 797 case IMAGE_RAW: {
ebd93cb6
LP
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;
f2068bcc
LP
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);
ebd93cb6
LP
811 break;
812 }
813
eb38edce
LP
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
ebd93cb6 834 default:
15411c0c 835 return -EOPNOTSUPP;
ebd93cb6
LP
836 }
837
838 return 0;
08682124
LP
839}
840
30535c16
LP
841int 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
30535c16
LP
857 if (!path_is_absolute(path))
858 return -EINVAL;
859
b6e953f2
LP
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
30535c16 868 if (stat(path, &st) >= 0) {
eb38edce
LP
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)
30535c16
LP
877 return -ENOMEM;
878 }
879
eb38edce
LP
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 }
30535c16
LP
887
888 if (p) {
7e7cddb2 889 mkdir_p("/run/systemd/nspawn/locks", 0700);
30535c16
LP
890
891 r = make_lock_file(p, operation, global);
892 if (r < 0) {
893 release_lock_file(&t);
894 return r;
895 }
546dbec5
LP
896 } else
897 *global = (LockFile) LOCK_FILE_INIT;
30535c16
LP
898
899 *local = t;
900 return 0;
901}
902
cb81cd80 903int image_set_limit(Image *i, uint64_t referenced_max) {
d6ce17c7
LP
904 assert(i);
905
d94c2b06 906 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
d6ce17c7
LP
907 return -EROFS;
908
909 if (i->type != IMAGE_SUBVOLUME)
15411c0c 910 return -EOPNOTSUPP;
d6ce17c7 911
5bcd08db
LP
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);
d6ce17c7
LP
920}
921
c7664c07
LP
922int 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
30535c16
LP
1034int 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
b6e953f2
LP
1045 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
1046 *ret = (LockFile) LOCK_FILE_INIT;
1047 return 0;
1048 }
1049
30535c16
LP
1050 if (streq(name, ".host"))
1051 return -EBUSY;
1052
7e7cddb2 1053 mkdir_p("/run/systemd/nspawn/locks", 0700);
63c372cb 1054 p = strjoina("/run/systemd/nspawn/locks/name-", name);
30535c16
LP
1055
1056 return make_lock_file(p, operation, ret);
1057}
1058
1059bool 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
cd61c3bf
LP
1076static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
1077 [IMAGE_DIRECTORY] = "directory",
1078 [IMAGE_SUBVOLUME] = "subvolume",
aceac2f0 1079 [IMAGE_RAW] = "raw",
eb38edce 1080 [IMAGE_BLOCK] = "block",
cd61c3bf
LP
1081};
1082
1083DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);