]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/machine-image.c
network: fix typo in log message
[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
c2ce6a3d 162 *ret = i;
cd61c3bf 163 i = NULL;
c2ce6a3d 164
cd61c3bf
LP
165 return 0;
166}
167
5fc7f358
LP
168static int image_make(
169 const char *pretty,
170 int dfd,
171 const char *path,
172 const char *filename,
173 Image **ret) {
174
c2ce6a3d 175 struct stat st;
5fc7f358 176 bool read_only;
cd61c3bf
LP
177 int r;
178
5fc7f358 179 assert(filename);
cd61c3bf 180
eb38edce
LP
181 /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block
182 * devices into /var/lib/machines/, and treat them normally. */
cd61c3bf 183
5fc7f358 184 if (fstatat(dfd, filename, &st, 0) < 0)
c2ce6a3d 185 return -errno;
cd61c3bf 186
5fc7f358
LP
187 read_only =
188 (path && path_startswith(path, "/usr")) ||
08ff5529 189 (faccessat(dfd, filename, W_OK, AT_EACCESS) < 0 && errno == EROFS);
86e339c8 190
c2ce6a3d 191 if (S_ISDIR(st.st_mode)) {
01b72568
LP
192 _cleanup_close_ int fd = -1;
193 unsigned file_attr = 0;
cd61c3bf 194
c2ce6a3d
LP
195 if (!ret)
196 return 1;
cd61c3bf 197
5fc7f358
LP
198 if (!pretty)
199 pretty = filename;
200
01b72568
LP
201 fd = openat(dfd, filename, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
202 if (fd < 0)
203 return -errno;
204
c2ce6a3d
LP
205 /* btrfs subvolumes have inode 256 */
206 if (st.st_ino == 256) {
cd61c3bf 207
21222ea5
LP
208 r = btrfs_is_filesystem(fd);
209 if (r < 0)
210 return r;
211 if (r) {
10f9c755 212 BtrfsSubvolInfo info;
cd61c3bf 213
c2ce6a3d 214 /* It's a btrfs subvolume */
cd61c3bf 215
5bcd08db 216 r = btrfs_subvol_get_info_fd(fd, 0, &info);
10f9c755
LP
217 if (r < 0)
218 return r;
c2ce6a3d
LP
219
220 r = image_new(IMAGE_SUBVOLUME,
5fc7f358 221 pretty,
c2ce6a3d 222 path,
5fc7f358
LP
223 filename,
224 info.read_only || read_only,
10f9c755 225 info.otime,
c2ce6a3d 226 0,
c2ce6a3d
LP
227 ret);
228 if (r < 0)
229 return r;
230
5bcd08db
LP
231 if (btrfs_quota_scan_ongoing(fd) == 0) {
232 BtrfsQuotaInfo quota;
b6b18498 233
5bcd08db
LP
234 r = btrfs_subvol_get_subtree_quota_fd(fd, 0, &quota);
235 if (r >= 0) {
236 (*ret)->usage = quota.referenced;
237 (*ret)->usage_exclusive = quota.exclusive;
238
239 (*ret)->limit = quota.referenced_max;
240 (*ret)->limit_exclusive = quota.exclusive_max;
241 }
b6b18498
LP
242 }
243
c2ce6a3d 244 return 1;
cd61c3bf 245 }
c2ce6a3d 246 }
cd61c3bf 247
01b72568
LP
248 /* If the IMMUTABLE bit is set, we consider the
249 * directory read-only. Since the ioctl is not
250 * supported everywhere we ignore failures. */
251 (void) read_attr_fd(fd, &file_attr);
cd61c3bf 252
01b72568 253 /* It's just a normal directory. */
c2ce6a3d 254 r = image_new(IMAGE_DIRECTORY,
5fc7f358 255 pretty,
c2ce6a3d 256 path,
5fc7f358 257 filename,
01b72568 258 read_only || (file_attr & FS_IMMUTABLE_FL),
c2ce6a3d
LP
259 0,
260 0,
261 ret);
262 if (r < 0)
263 return r;
cd61c3bf 264
c2ce6a3d 265 return 1;
cd61c3bf 266
aceac2f0 267 } else if (S_ISREG(st.st_mode) && endswith(filename, ".raw")) {
10f9c755 268 usec_t crtime = 0;
cd61c3bf 269
aceac2f0 270 /* It's a RAW disk image */
cd61c3bf 271
c2ce6a3d
LP
272 if (!ret)
273 return 1;
cd61c3bf 274
5fc7f358 275 fd_getcrtime_at(dfd, filename, &crtime, 0);
10f9c755 276
5fc7f358
LP
277 if (!pretty)
278 pretty = strndupa(filename, strlen(filename) - 4);
10f9c755 279
aceac2f0 280 r = image_new(IMAGE_RAW,
5fc7f358 281 pretty,
c2ce6a3d 282 path,
5fc7f358
LP
283 filename,
284 !(st.st_mode & 0222) || read_only,
10f9c755 285 crtime,
c2ce6a3d 286 timespec_load(&st.st_mtim),
c2ce6a3d
LP
287 ret);
288 if (r < 0)
289 return r;
cd61c3bf 290
c19de711 291 (*ret)->usage = (*ret)->usage_exclusive = st.st_blocks * 512;
b6b18498
LP
292 (*ret)->limit = (*ret)->limit_exclusive = st.st_size;
293
c2ce6a3d 294 return 1;
eb38edce
LP
295
296 } else if (S_ISBLK(st.st_mode)) {
297 _cleanup_close_ int block_fd = -1;
298 uint64_t size = UINT64_MAX;
299
300 /* A block device */
301
302 if (!ret)
303 return 1;
304
305 if (!pretty)
306 pretty = filename;
307
308 block_fd = openat(dfd, filename, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
309 if (block_fd < 0)
310 log_debug_errno(errno, "Failed to open block device %s/%s, ignoring: %m", path, filename);
311 else {
312 if (fstat(block_fd, &st) < 0)
313 return -errno;
314 if (!S_ISBLK(st.st_mode)) /* Verify that what we opened is actually what we think it is */
315 return -ENOTTY;
316
317 if (!read_only) {
318 int state = 0;
319
320 if (ioctl(block_fd, BLKROGET, &state) < 0)
321 log_debug_errno(errno, "Failed to issue BLKROGET on device %s/%s, ignoring: %m", path, filename);
322 else if (state)
323 read_only = true;
324 }
325
326 if (ioctl(block_fd, BLKGETSIZE64, &size) < 0)
327 log_debug_errno(errno, "Failed to issue BLKFLSBUF on device %s/%s, ignoring: %m", path, filename);
328
329 block_fd = safe_close(block_fd);
330 }
331
332 r = image_new(IMAGE_BLOCK,
333 pretty,
334 path,
335 filename,
336 !(st.st_mode & 0222) || read_only,
337 0,
338 0,
339 ret);
340 if (r < 0)
341 return r;
342
343 if (size != 0 && size != UINT64_MAX)
344 (*ret)->usage = (*ret)->usage_exclusive = (*ret)->limit = (*ret)->limit_exclusive = size;
345
346 return 1;
c2ce6a3d 347 }
cd61c3bf 348
c2ce6a3d
LP
349 return 0;
350}
cd61c3bf 351
c2ce6a3d
LP
352int image_find(const char *name, Image **ret) {
353 const char *path;
354 int r;
cd61c3bf 355
c2ce6a3d 356 assert(name);
cd61c3bf 357
c2ce6a3d
LP
358 /* There are no images with invalid names */
359 if (!image_name_is_valid(name))
360 return 0;
cd61c3bf 361
c2ce6a3d
LP
362 NULSTR_FOREACH(path, image_search_path) {
363 _cleanup_closedir_ DIR *d = NULL;
cd61c3bf 364
c2ce6a3d
LP
365 d = opendir(path);
366 if (!d) {
367 if (errno == ENOENT)
368 continue;
cd61c3bf 369
c2ce6a3d
LP
370 return -errno;
371 }
cd61c3bf 372
5fc7f358 373 r = image_make(NULL, dirfd(d), path, name, ret);
4c701096 374 if (IN_SET(r, 0, -ENOENT)) {
aceac2f0 375 _cleanup_free_ char *raw = NULL;
5fc7f358 376
aceac2f0
LP
377 raw = strappend(name, ".raw");
378 if (!raw)
5fc7f358
LP
379 return -ENOMEM;
380
aceac2f0 381 r = image_make(NULL, dirfd(d), path, raw, ret);
4c701096 382 if (IN_SET(r, 0, -ENOENT))
5fc7f358
LP
383 continue;
384 }
c2ce6a3d
LP
385 if (r < 0)
386 return r;
cd61c3bf 387
c2ce6a3d
LP
388 return 1;
389 }
390
5fc7f358 391 if (streq(name, ".host"))
27c88c4e 392 return image_make(".host", AT_FDCWD, NULL, "/", ret);
5fc7f358 393
c2ce6a3d
LP
394 return 0;
395};
396
397int image_discover(Hashmap *h) {
398 const char *path;
399 int r;
400
401 assert(h);
402
403 NULSTR_FOREACH(path, image_search_path) {
404 _cleanup_closedir_ DIR *d = NULL;
405 struct dirent *de;
406
407 d = opendir(path);
408 if (!d) {
409 if (errno == ENOENT)
a67a4c8c 410 continue;
c2ce6a3d
LP
411
412 return -errno;
413 }
414
415 FOREACH_DIRENT_ALL(de, d, return -errno) {
416 _cleanup_(image_unrefp) Image *image = NULL;
417
418 if (!image_name_is_valid(de->d_name))
419 continue;
420
421 if (hashmap_contains(h, de->d_name))
422 continue;
423
5fc7f358 424 r = image_make(NULL, dirfd(d), path, de->d_name, &image);
4c701096 425 if (IN_SET(r, 0, -ENOENT))
c2ce6a3d
LP
426 continue;
427 if (r < 0)
428 return r;
429
430 r = hashmap_put(h, image->name, image);
431 if (r < 0)
432 return r;
433
434 image = NULL;
cd61c3bf
LP
435 }
436 }
437
5fc7f358
LP
438 if (!hashmap_contains(h, ".host")) {
439 _cleanup_(image_unrefp) Image *image = NULL;
440
441 r = image_make(".host", AT_FDCWD, NULL, "/", &image);
442 if (r < 0)
443 return r;
444
445 r = hashmap_put(h, image->name, image);
446 if (r < 0)
447 return r;
448
449 image = NULL;
450
451 }
452
cd61c3bf
LP
453 return 0;
454}
455
08682124 456int image_remove(Image *i) {
30535c16 457 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
8e0b6570 458 _cleanup_strv_free_ char **settings = NULL;
bafbac4e 459 _cleanup_free_ char *roothash = NULL;
8e0b6570 460 char **j;
30535c16
LP
461 int r;
462
08682124
LP
463 assert(i);
464
d94c2b06 465 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
08682124
LP
466 return -EROFS;
467
8e0b6570
LP
468 settings = image_settings_path(i);
469 if (!settings)
470 return -ENOMEM;
471
bafbac4e
LP
472 roothash = image_roothash_path(i);
473 if (!roothash)
474 return -ENOMEM;
475
30535c16
LP
476 /* Make sure we don't interfere with a running nspawn */
477 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
478 if (r < 0)
479 return r;
480
ebd93cb6
LP
481 switch (i->type) {
482
483 case IMAGE_SUBVOLUME:
9fb0b9c7
LP
484
485 /* Let's unlink first, maybe it is a symlink? If that works we are happy. Otherwise, let's get out the
486 * big guns */
487 if (unlink(i->path) < 0) {
488 r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
489 if (r < 0)
490 return r;
491 }
492
8e0b6570 493 break;
ebd93cb6
LP
494
495 case IMAGE_DIRECTORY:
01b72568 496 /* Allow deletion of read-only directories */
a67d68b8 497 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
8e0b6570
LP
498 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
499 if (r < 0)
500 return r;
501
502 break;
01b72568 503
eb38edce
LP
504 case IMAGE_BLOCK:
505
506 /* If this is inside of /dev, then it's a real block device, hence let's not touch the device node
507 * itself (but let's remove the stuff stored alongside it). If it's anywhere else, let's try to unlink
508 * the thing (it's most likely a symlink after all). */
509
510 if (path_startswith(i->path, "/dev"))
511 break;
512
4831981d 513 _fallthrough_;
aceac2f0 514 case IMAGE_RAW:
41d1ed05
LP
515 if (unlink(i->path) < 0)
516 return -errno;
8e0b6570 517 break;
ebd93cb6
LP
518
519 default:
15411c0c 520 return -EOPNOTSUPP;
ebd93cb6 521 }
8e0b6570
LP
522
523 STRV_FOREACH(j, settings) {
524 if (unlink(*j) < 0 && errno != ENOENT)
525 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
526 }
527
bafbac4e
LP
528 if (unlink(roothash) < 0 && errno != ENOENT)
529 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash);
530
8e0b6570
LP
531 return 0;
532}
533
bafbac4e 534static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
8e0b6570
LP
535 _cleanup_free_ char *rs = NULL;
536 const char *fn;
537
bafbac4e 538 fn = strjoina(new_name, suffix);
8e0b6570
LP
539
540 rs = file_in_same_dir(path, fn);
541 if (!rs)
542 return -ENOMEM;
543
544 return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
ebd93cb6
LP
545}
546
547int image_rename(Image *i, const char *new_name) {
30535c16 548 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
bafbac4e 549 _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
8e0b6570 550 _cleanup_strv_free_ char **settings = NULL;
01b72568 551 unsigned file_attr = 0;
8e0b6570 552 char **j;
ebd93cb6
LP
553 int r;
554
555 assert(i);
556
557 if (!image_name_is_valid(new_name))
558 return -EINVAL;
559
d94c2b06 560 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
ebd93cb6
LP
561 return -EROFS;
562
8e0b6570
LP
563 settings = image_settings_path(i);
564 if (!settings)
565 return -ENOMEM;
566
bafbac4e
LP
567 roothash = image_roothash_path(i);
568 if (!roothash)
569 return -ENOMEM;
570
30535c16
LP
571 /* Make sure we don't interfere with a running nspawn */
572 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
573 if (r < 0)
574 return r;
575
576 /* Make sure nobody takes the new name, between the time we
577 * checked it is currently unused in all search paths, and the
f8e2f4d6 578 * time we take possession of it */
30535c16
LP
579 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
580 if (r < 0)
581 return r;
582
ebd93cb6
LP
583 r = image_find(new_name, NULL);
584 if (r < 0)
585 return r;
586 if (r > 0)
587 return -EEXIST;
588
589 switch (i->type) {
590
ebd93cb6 591 case IMAGE_DIRECTORY:
01b72568
LP
592 /* Turn of the immutable bit while we rename the image, so that we can rename it */
593 (void) read_attr_path(i->path, &file_attr);
594
595 if (file_attr & FS_IMMUTABLE_FL)
a67d68b8 596 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
01b72568 597
4831981d 598 _fallthrough_;
01b72568 599 case IMAGE_SUBVOLUME:
ebd93cb6
LP
600 new_path = file_in_same_dir(i->path, new_name);
601 break;
602
eb38edce
LP
603 case IMAGE_BLOCK:
604
605 /* Refuse renaming raw block devices in /dev, the names are picked by udev after all. */
606 if (path_startswith(i->path, "/dev"))
607 return -EROFS;
608
609 new_path = file_in_same_dir(i->path, new_name);
610 break;
611
aceac2f0 612 case IMAGE_RAW: {
ebd93cb6
LP
613 const char *fn;
614
63c372cb 615 fn = strjoina(new_name, ".raw");
ebd93cb6
LP
616 new_path = file_in_same_dir(i->path, fn);
617 break;
618 }
619
620 default:
15411c0c 621 return -EOPNOTSUPP;
ebd93cb6
LP
622 }
623
624 if (!new_path)
625 return -ENOMEM;
626
627 nn = strdup(new_name);
628 if (!nn)
629 return -ENOMEM;
630
f85ef957
AC
631 r = rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path);
632 if (r < 0)
633 return r;
ebd93cb6 634
01b72568
LP
635 /* Restore the immutable bit, if it was set before */
636 if (file_attr & FS_IMMUTABLE_FL)
a67d68b8 637 (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
01b72568 638
f9ecfd3b
DL
639 free_and_replace(i->path, new_path);
640 free_and_replace(i->name, nn);
ebd93cb6 641
8e0b6570 642 STRV_FOREACH(j, settings) {
bafbac4e 643 r = rename_auxiliary_file(*j, new_name, ".nspawn");
8e0b6570
LP
644 if (r < 0 && r != -ENOENT)
645 log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
646 }
647
bafbac4e
LP
648 r = rename_auxiliary_file(roothash, new_name, ".roothash");
649 if (r < 0 && r != -ENOENT)
650 log_debug_errno(r, "Failed to rename roothash file %s, ignoring: %m", roothash);
651
ebd93cb6
LP
652 return 0;
653}
654
bafbac4e 655static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
8e0b6570
LP
656 _cleanup_free_ char *rs = NULL;
657 const char *fn;
658
bafbac4e 659 fn = strjoina(new_name, suffix);
8e0b6570
LP
660
661 rs = file_in_same_dir(path, fn);
662 if (!rs)
663 return -ENOMEM;
664
1c876927 665 return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK);
8e0b6570
LP
666}
667
ebd93cb6 668int image_clone(Image *i, const char *new_name, bool read_only) {
30535c16 669 _cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT;
8e0b6570 670 _cleanup_strv_free_ char **settings = NULL;
bafbac4e 671 _cleanup_free_ char *roothash = NULL;
ebd93cb6 672 const char *new_path;
8e0b6570 673 char **j;
ebd93cb6
LP
674 int r;
675
676 assert(i);
677
678 if (!image_name_is_valid(new_name))
679 return -EINVAL;
680
8e0b6570
LP
681 settings = image_settings_path(i);
682 if (!settings)
683 return -ENOMEM;
684
bafbac4e
LP
685 roothash = image_roothash_path(i);
686 if (!roothash)
687 return -ENOMEM;
688
30535c16
LP
689 /* Make sure nobody takes the new name, between the time we
690 * checked it is currently unused in all search paths, and the
f8e2f4d6 691 * time we take possession of it */
30535c16
LP
692 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
693 if (r < 0)
694 return r;
695
ebd93cb6
LP
696 r = image_find(new_name, NULL);
697 if (r < 0)
698 return r;
699 if (r > 0)
700 return -EEXIST;
701
702 switch (i->type) {
703
704 case IMAGE_SUBVOLUME:
705 case IMAGE_DIRECTORY:
9a50e3ca 706 /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
13e785f7 707 * directory. */
9a50e3ca 708
63c372cb 709 new_path = strjoina("/var/lib/machines/", new_name);
ebd93cb6 710
17cbb288
LP
711 r = btrfs_subvol_snapshot(i->path, new_path,
712 (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
713 BTRFS_SNAPSHOT_FALLBACK_COPY |
714 BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
715 BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
716 BTRFS_SNAPSHOT_RECURSIVE |
717 BTRFS_SNAPSHOT_QUOTA);
718 if (r >= 0)
9a50e3ca 719 /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
8120ee28 720 (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
5bcd08db 721
ebd93cb6
LP
722 break;
723
aceac2f0 724 case IMAGE_RAW:
63c372cb 725 new_path = strjoina("/var/lib/machines/", new_name, ".raw");
ebd93cb6 726
1c876927 727 r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
ebd93cb6
LP
728 break;
729
eb38edce 730 case IMAGE_BLOCK:
ebd93cb6 731 default:
15411c0c 732 return -EOPNOTSUPP;
ebd93cb6
LP
733 }
734
735 if (r < 0)
736 return r;
737
8e0b6570 738 STRV_FOREACH(j, settings) {
bafbac4e 739 r = clone_auxiliary_file(*j, new_name, ".nspawn");
8e0b6570
LP
740 if (r < 0 && r != -ENOENT)
741 log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
742 }
743
bafbac4e
LP
744 r = clone_auxiliary_file(roothash, new_name, ".roothash");
745 if (r < 0 && r != -ENOENT)
746 log_debug_errno(r, "Failed to clone root hash file %s, ignoring: %m", roothash);
747
ebd93cb6
LP
748 return 0;
749}
750
751int image_read_only(Image *i, bool b) {
30535c16 752 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
ebd93cb6 753 int r;
c7664c07 754
ebd93cb6
LP
755 assert(i);
756
d94c2b06 757 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
ebd93cb6
LP
758 return -EROFS;
759
30535c16
LP
760 /* Make sure we don't interfere with a running nspawn */
761 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
762 if (r < 0)
763 return r;
764
ebd93cb6
LP
765 switch (i->type) {
766
767 case IMAGE_SUBVOLUME:
5bcd08db
LP
768
769 /* Note that we set the flag only on the top-level
770 * subvolume of the image. */
771
ebd93cb6
LP
772 r = btrfs_subvol_set_read_only(i->path, b);
773 if (r < 0)
774 return r;
01b72568
LP
775
776 break;
777
778 case IMAGE_DIRECTORY:
779 /* For simple directory trees we cannot use the access
780 mode of the top-level directory, since it has an
781 effect on the container itself. However, we can
782 use the "immutable" flag, to at least make the
783 top-level directory read-only. It's not as good as
784 a read-only subvolume, but at least something, and
13e785f7 785 we can read the value back. */
01b72568 786
a67d68b8 787 r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
01b72568
LP
788 if (r < 0)
789 return r;
790
ebd93cb6
LP
791 break;
792
aceac2f0 793 case IMAGE_RAW: {
ebd93cb6
LP
794 struct stat st;
795
796 if (stat(i->path, &st) < 0)
797 return -errno;
798
799 if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0)
800 return -errno;
f2068bcc
LP
801
802 /* If the images is now read-only, it's a good time to
803 * defrag it, given that no write patterns will
804 * fragment it again. */
805 if (b)
806 (void) btrfs_defrag(i->path);
ebd93cb6
LP
807 break;
808 }
809
eb38edce
LP
810 case IMAGE_BLOCK: {
811 _cleanup_close_ int fd = -1;
812 struct stat st;
813 int state = b;
814
815 fd = open(i->path, O_CLOEXEC|O_RDONLY|O_NONBLOCK|O_NOCTTY);
816 if (fd < 0)
817 return -errno;
818
819 if (fstat(fd, &st) < 0)
820 return -errno;
821 if (!S_ISBLK(st.st_mode))
822 return -ENOTTY;
823
824 if (ioctl(fd, BLKROSET, &state) < 0)
825 return -errno;
826
827 break;
828 }
829
ebd93cb6 830 default:
15411c0c 831 return -EOPNOTSUPP;
ebd93cb6
LP
832 }
833
834 return 0;
08682124
LP
835}
836
30535c16
LP
837int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local) {
838 _cleanup_free_ char *p = NULL;
839 LockFile t = LOCK_FILE_INIT;
840 struct stat st;
841 int r;
842
843 assert(path);
844 assert(global);
845 assert(local);
846
847 /* Locks an image path. This actually creates two locks: one
848 * "local" one, next to the image path itself, which might be
849 * shared via NFS. And another "global" one, in /run, that
850 * uses the device/inode number. This has the benefit that we
851 * can even lock a tree that is a mount point, correctly. */
852
30535c16
LP
853 if (!path_is_absolute(path))
854 return -EINVAL;
855
b6e953f2
LP
856 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
857 *local = *global = (LockFile) LOCK_FILE_INIT;
858 return 0;
859 }
860
861 if (path_equal(path, "/"))
862 return -EBUSY;
863
30535c16 864 if (stat(path, &st) >= 0) {
eb38edce
LP
865 if (S_ISBLK(st.st_mode))
866 r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev));
867 else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))
868 r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino);
869 else
870 return -ENOTTY;
871
872 if (r < 0)
30535c16
LP
873 return -ENOMEM;
874 }
875
eb38edce
LP
876 /* For block devices we don't need the "local" lock, as the major/minor lock above should be sufficient, since
877 * block devices are device local anyway. */
878 if (!path_startswith(path, "/dev")) {
879 r = make_lock_file_for(path, operation, &t);
8be17c9b
LT
880 if (r < 0) {
881 if ((operation & LOCK_SH) && r == -EROFS)
771b7ead 882 log_debug_errno(r, "Failed to create shared lock for '%s', ignoring: %m", path);
8be17c9b
LT
883 else
884 return r;
885 }
eb38edce 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
62570f6f 941 r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
c7664c07
LP
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
62570f6f 952 r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
c7664c07
LP
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
62570f6f 970 r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
c7664c07
LP
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
62570f6f 981 r = chase_symlinks("/etc/os-release", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
c7664c07 982 if (r == -ENOENT)
62570f6f 983 r = chase_symlinks("/usr/lib/os-release", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
c7664c07
LP
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);