]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/machine-image.c
Replace free and return NULL with return mfree
[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
460void image_hashmap_free(Hashmap *map) {
461 Image *i;
462
463 while ((i = hashmap_steal_first(map)))
464 image_unref(i);
465
466 hashmap_free(map);
467}
468
08682124 469int image_remove(Image *i) {
30535c16 470 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
8e0b6570 471 _cleanup_strv_free_ char **settings = NULL;
bafbac4e 472 _cleanup_free_ char *roothash = NULL;
8e0b6570 473 char **j;
30535c16
LP
474 int r;
475
08682124
LP
476 assert(i);
477
d94c2b06 478 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
08682124
LP
479 return -EROFS;
480
8e0b6570
LP
481 settings = image_settings_path(i);
482 if (!settings)
483 return -ENOMEM;
484
bafbac4e
LP
485 roothash = image_roothash_path(i);
486 if (!roothash)
487 return -ENOMEM;
488
30535c16
LP
489 /* Make sure we don't interfere with a running nspawn */
490 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
491 if (r < 0)
492 return r;
493
ebd93cb6
LP
494 switch (i->type) {
495
496 case IMAGE_SUBVOLUME:
9fb0b9c7
LP
497
498 /* Let's unlink first, maybe it is a symlink? If that works we are happy. Otherwise, let's get out the
499 * big guns */
500 if (unlink(i->path) < 0) {
501 r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
502 if (r < 0)
503 return r;
504 }
505
8e0b6570 506 break;
ebd93cb6
LP
507
508 case IMAGE_DIRECTORY:
01b72568 509 /* Allow deletion of read-only directories */
a67d68b8 510 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
8e0b6570
LP
511 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
512 if (r < 0)
513 return r;
514
515 break;
01b72568 516
eb38edce
LP
517 case IMAGE_BLOCK:
518
519 /* If this is inside of /dev, then it's a real block device, hence let's not touch the device node
520 * itself (but let's remove the stuff stored alongside it). If it's anywhere else, let's try to unlink
521 * the thing (it's most likely a symlink after all). */
522
523 if (path_startswith(i->path, "/dev"))
524 break;
525
4831981d 526 _fallthrough_;
aceac2f0 527 case IMAGE_RAW:
41d1ed05
LP
528 if (unlink(i->path) < 0)
529 return -errno;
8e0b6570 530 break;
ebd93cb6
LP
531
532 default:
15411c0c 533 return -EOPNOTSUPP;
ebd93cb6 534 }
8e0b6570
LP
535
536 STRV_FOREACH(j, settings) {
537 if (unlink(*j) < 0 && errno != ENOENT)
538 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
539 }
540
bafbac4e
LP
541 if (unlink(roothash) < 0 && errno != ENOENT)
542 log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash);
543
8e0b6570
LP
544 return 0;
545}
546
bafbac4e 547static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
8e0b6570
LP
548 _cleanup_free_ char *rs = NULL;
549 const char *fn;
550
bafbac4e 551 fn = strjoina(new_name, suffix);
8e0b6570
LP
552
553 rs = file_in_same_dir(path, fn);
554 if (!rs)
555 return -ENOMEM;
556
557 return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
ebd93cb6
LP
558}
559
560int image_rename(Image *i, const char *new_name) {
30535c16 561 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
bafbac4e 562 _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
8e0b6570 563 _cleanup_strv_free_ char **settings = NULL;
01b72568 564 unsigned file_attr = 0;
8e0b6570 565 char **j;
ebd93cb6
LP
566 int r;
567
568 assert(i);
569
570 if (!image_name_is_valid(new_name))
571 return -EINVAL;
572
d94c2b06 573 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
ebd93cb6
LP
574 return -EROFS;
575
8e0b6570
LP
576 settings = image_settings_path(i);
577 if (!settings)
578 return -ENOMEM;
579
bafbac4e
LP
580 roothash = image_roothash_path(i);
581 if (!roothash)
582 return -ENOMEM;
583
30535c16
LP
584 /* Make sure we don't interfere with a running nspawn */
585 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
586 if (r < 0)
587 return r;
588
589 /* Make sure nobody takes the new name, between the time we
590 * checked it is currently unused in all search paths, and the
f8e2f4d6 591 * time we take possession of it */
30535c16
LP
592 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
593 if (r < 0)
594 return r;
595
ebd93cb6
LP
596 r = image_find(new_name, NULL);
597 if (r < 0)
598 return r;
599 if (r > 0)
600 return -EEXIST;
601
602 switch (i->type) {
603
ebd93cb6 604 case IMAGE_DIRECTORY:
01b72568
LP
605 /* Turn of the immutable bit while we rename the image, so that we can rename it */
606 (void) read_attr_path(i->path, &file_attr);
607
608 if (file_attr & FS_IMMUTABLE_FL)
a67d68b8 609 (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
01b72568 610
4831981d 611 _fallthrough_;
01b72568 612 case IMAGE_SUBVOLUME:
ebd93cb6
LP
613 new_path = file_in_same_dir(i->path, new_name);
614 break;
615
eb38edce
LP
616 case IMAGE_BLOCK:
617
618 /* Refuse renaming raw block devices in /dev, the names are picked by udev after all. */
619 if (path_startswith(i->path, "/dev"))
620 return -EROFS;
621
622 new_path = file_in_same_dir(i->path, new_name);
623 break;
624
aceac2f0 625 case IMAGE_RAW: {
ebd93cb6
LP
626 const char *fn;
627
63c372cb 628 fn = strjoina(new_name, ".raw");
ebd93cb6
LP
629 new_path = file_in_same_dir(i->path, fn);
630 break;
631 }
632
633 default:
15411c0c 634 return -EOPNOTSUPP;
ebd93cb6
LP
635 }
636
637 if (!new_path)
638 return -ENOMEM;
639
640 nn = strdup(new_name);
641 if (!nn)
642 return -ENOMEM;
643
f85ef957
AC
644 r = rename_noreplace(AT_FDCWD, i->path, AT_FDCWD, new_path);
645 if (r < 0)
646 return r;
ebd93cb6 647
01b72568
LP
648 /* Restore the immutable bit, if it was set before */
649 if (file_attr & FS_IMMUTABLE_FL)
a67d68b8 650 (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
01b72568 651
ebd93cb6
LP
652 free(i->path);
653 i->path = new_path;
654 new_path = NULL;
655
656 free(i->name);
657 i->name = nn;
658 nn = NULL;
659
8e0b6570 660 STRV_FOREACH(j, settings) {
bafbac4e 661 r = rename_auxiliary_file(*j, new_name, ".nspawn");
8e0b6570
LP
662 if (r < 0 && r != -ENOENT)
663 log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
664 }
665
bafbac4e
LP
666 r = rename_auxiliary_file(roothash, new_name, ".roothash");
667 if (r < 0 && r != -ENOENT)
668 log_debug_errno(r, "Failed to rename roothash file %s, ignoring: %m", roothash);
669
ebd93cb6
LP
670 return 0;
671}
672
bafbac4e 673static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
8e0b6570
LP
674 _cleanup_free_ char *rs = NULL;
675 const char *fn;
676
bafbac4e 677 fn = strjoina(new_name, suffix);
8e0b6570
LP
678
679 rs = file_in_same_dir(path, fn);
680 if (!rs)
681 return -ENOMEM;
682
1c876927 683 return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK);
8e0b6570
LP
684}
685
ebd93cb6 686int image_clone(Image *i, const char *new_name, bool read_only) {
30535c16 687 _cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT;
8e0b6570 688 _cleanup_strv_free_ char **settings = NULL;
bafbac4e 689 _cleanup_free_ char *roothash = NULL;
ebd93cb6 690 const char *new_path;
8e0b6570 691 char **j;
ebd93cb6
LP
692 int r;
693
694 assert(i);
695
696 if (!image_name_is_valid(new_name))
697 return -EINVAL;
698
8e0b6570
LP
699 settings = image_settings_path(i);
700 if (!settings)
701 return -ENOMEM;
702
bafbac4e
LP
703 roothash = image_roothash_path(i);
704 if (!roothash)
705 return -ENOMEM;
706
30535c16
LP
707 /* Make sure nobody takes the new name, between the time we
708 * checked it is currently unused in all search paths, and the
f8e2f4d6 709 * time we take possession of it */
30535c16
LP
710 r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
711 if (r < 0)
712 return r;
713
ebd93cb6
LP
714 r = image_find(new_name, NULL);
715 if (r < 0)
716 return r;
717 if (r > 0)
718 return -EEXIST;
719
720 switch (i->type) {
721
722 case IMAGE_SUBVOLUME:
723 case IMAGE_DIRECTORY:
9a50e3ca 724 /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
13e785f7 725 * directory. */
9a50e3ca 726
63c372cb 727 new_path = strjoina("/var/lib/machines/", new_name);
ebd93cb6 728
17cbb288
LP
729 r = btrfs_subvol_snapshot(i->path, new_path,
730 (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
731 BTRFS_SNAPSHOT_FALLBACK_COPY |
732 BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
733 BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
734 BTRFS_SNAPSHOT_RECURSIVE |
735 BTRFS_SNAPSHOT_QUOTA);
736 if (r >= 0)
9a50e3ca 737 /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
8120ee28 738 (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
5bcd08db 739
ebd93cb6
LP
740 break;
741
aceac2f0 742 case IMAGE_RAW:
63c372cb 743 new_path = strjoina("/var/lib/machines/", new_name, ".raw");
ebd93cb6 744
1c876927 745 r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
ebd93cb6
LP
746 break;
747
eb38edce 748 case IMAGE_BLOCK:
ebd93cb6 749 default:
15411c0c 750 return -EOPNOTSUPP;
ebd93cb6
LP
751 }
752
753 if (r < 0)
754 return r;
755
8e0b6570 756 STRV_FOREACH(j, settings) {
bafbac4e 757 r = clone_auxiliary_file(*j, new_name, ".nspawn");
8e0b6570
LP
758 if (r < 0 && r != -ENOENT)
759 log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
760 }
761
bafbac4e
LP
762 r = clone_auxiliary_file(roothash, new_name, ".roothash");
763 if (r < 0 && r != -ENOENT)
764 log_debug_errno(r, "Failed to clone root hash file %s, ignoring: %m", roothash);
765
ebd93cb6
LP
766 return 0;
767}
768
769int image_read_only(Image *i, bool b) {
30535c16 770 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
ebd93cb6 771 int r;
c7664c07 772
ebd93cb6
LP
773 assert(i);
774
d94c2b06 775 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
ebd93cb6
LP
776 return -EROFS;
777
30535c16
LP
778 /* Make sure we don't interfere with a running nspawn */
779 r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
780 if (r < 0)
781 return r;
782
ebd93cb6
LP
783 switch (i->type) {
784
785 case IMAGE_SUBVOLUME:
5bcd08db
LP
786
787 /* Note that we set the flag only on the top-level
788 * subvolume of the image. */
789
ebd93cb6
LP
790 r = btrfs_subvol_set_read_only(i->path, b);
791 if (r < 0)
792 return r;
01b72568
LP
793
794 break;
795
796 case IMAGE_DIRECTORY:
797 /* For simple directory trees we cannot use the access
798 mode of the top-level directory, since it has an
799 effect on the container itself. However, we can
800 use the "immutable" flag, to at least make the
801 top-level directory read-only. It's not as good as
802 a read-only subvolume, but at least something, and
13e785f7 803 we can read the value back. */
01b72568 804
a67d68b8 805 r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
01b72568
LP
806 if (r < 0)
807 return r;
808
ebd93cb6
LP
809 break;
810
aceac2f0 811 case IMAGE_RAW: {
ebd93cb6
LP
812 struct stat st;
813
814 if (stat(i->path, &st) < 0)
815 return -errno;
816
817 if (chmod(i->path, (st.st_mode & 0444) | (b ? 0000 : 0200)) < 0)
818 return -errno;
f2068bcc
LP
819
820 /* If the images is now read-only, it's a good time to
821 * defrag it, given that no write patterns will
822 * fragment it again. */
823 if (b)
824 (void) btrfs_defrag(i->path);
ebd93cb6
LP
825 break;
826 }
827
eb38edce
LP
828 case IMAGE_BLOCK: {
829 _cleanup_close_ int fd = -1;
830 struct stat st;
831 int state = b;
832
833 fd = open(i->path, O_CLOEXEC|O_RDONLY|O_NONBLOCK|O_NOCTTY);
834 if (fd < 0)
835 return -errno;
836
837 if (fstat(fd, &st) < 0)
838 return -errno;
839 if (!S_ISBLK(st.st_mode))
840 return -ENOTTY;
841
842 if (ioctl(fd, BLKROSET, &state) < 0)
843 return -errno;
844
845 break;
846 }
847
ebd93cb6 848 default:
15411c0c 849 return -EOPNOTSUPP;
ebd93cb6
LP
850 }
851
852 return 0;
08682124
LP
853}
854
30535c16
LP
855int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local) {
856 _cleanup_free_ char *p = NULL;
857 LockFile t = LOCK_FILE_INIT;
858 struct stat st;
859 int r;
860
861 assert(path);
862 assert(global);
863 assert(local);
864
865 /* Locks an image path. This actually creates two locks: one
866 * "local" one, next to the image path itself, which might be
867 * shared via NFS. And another "global" one, in /run, that
868 * uses the device/inode number. This has the benefit that we
869 * can even lock a tree that is a mount point, correctly. */
870
30535c16
LP
871 if (!path_is_absolute(path))
872 return -EINVAL;
873
b6e953f2
LP
874 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
875 *local = *global = (LockFile) LOCK_FILE_INIT;
876 return 0;
877 }
878
879 if (path_equal(path, "/"))
880 return -EBUSY;
881
30535c16 882 if (stat(path, &st) >= 0) {
eb38edce
LP
883 if (S_ISBLK(st.st_mode))
884 r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev));
885 else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))
886 r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino);
887 else
888 return -ENOTTY;
889
890 if (r < 0)
30535c16
LP
891 return -ENOMEM;
892 }
893
eb38edce
LP
894 /* For block devices we don't need the "local" lock, as the major/minor lock above should be sufficient, since
895 * block devices are device local anyway. */
896 if (!path_startswith(path, "/dev")) {
897 r = make_lock_file_for(path, operation, &t);
898 if (r < 0)
899 return r;
900 }
30535c16
LP
901
902 if (p) {
7e7cddb2 903 mkdir_p("/run/systemd/nspawn/locks", 0700);
30535c16
LP
904
905 r = make_lock_file(p, operation, global);
906 if (r < 0) {
907 release_lock_file(&t);
908 return r;
909 }
546dbec5
LP
910 } else
911 *global = (LockFile) LOCK_FILE_INIT;
30535c16
LP
912
913 *local = t;
914 return 0;
915}
916
cb81cd80 917int image_set_limit(Image *i, uint64_t referenced_max) {
d6ce17c7
LP
918 assert(i);
919
d94c2b06 920 if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
d6ce17c7
LP
921 return -EROFS;
922
923 if (i->type != IMAGE_SUBVOLUME)
15411c0c 924 return -EOPNOTSUPP;
d6ce17c7 925
5bcd08db
LP
926 /* We set the quota both for the subvolume as well as for the
927 * subtree. The latter is mostly for historical reasons, since
928 * we didn't use to have a concept of subtree quota, and hence
929 * only modified the subvolume quota. */
930
931 (void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
932 (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
933 return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
d6ce17c7
LP
934}
935
c7664c07
LP
936int image_read_metadata(Image *i) {
937 _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
938 int r;
939
940 assert(i);
941
942 r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock);
943 if (r < 0)
944 return r;
945
946 switch (i->type) {
947
948 case IMAGE_SUBVOLUME:
949 case IMAGE_DIRECTORY: {
950 _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
951 sd_id128_t machine_id = SD_ID128_NULL;
952 _cleanup_free_ char *hostname = NULL;
953 _cleanup_free_ char *path = NULL;
954
955 r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT, &path);
956 if (r < 0 && r != -ENOENT)
957 log_debug_errno(r, "Failed to chase /etc/hostname in image %s: %m", i->name);
958 else if (r >= 0) {
959 r = read_etc_hostname(path, &hostname);
960 if (r < 0)
961 log_debug_errno(errno, "Failed to read /etc/hostname of image %s: %m", i->name);
962 }
963
964 path = mfree(path);
965
966 r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT, &path);
967 if (r < 0 && r != -ENOENT)
968 log_debug_errno(r, "Failed to chase /etc/machine-id in image %s: %m", i->name);
969 else if (r >= 0) {
970 _cleanup_close_ int fd = -1;
971
972 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
973 if (fd < 0)
974 log_debug_errno(errno, "Failed to open %s: %m", path);
975 else {
976 r = id128_read_fd(fd, ID128_PLAIN, &machine_id);
977 if (r < 0)
978 log_debug_errno(r, "Image %s contains invalid machine ID.", i->name);
979 }
980 }
981
982 path = mfree(path);
983
984 r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT, &path);
985 if (r < 0 && r != -ENOENT)
986 log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name);
987 else if (r >= 0) {
988 r = load_env_file_pairs(NULL, path, NULL, &machine_info);
989 if (r < 0)
990 log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name);
991 }
992
993 path = mfree(path);
994
995 r = chase_symlinks("/etc/os-release", i->path, CHASE_PREFIX_ROOT, &path);
996 if (r == -ENOENT)
997 r = chase_symlinks("/usr/lib/os-release", i->path, CHASE_PREFIX_ROOT, &path);
998 if (r < 0 && r != -ENOENT)
999 log_debug_errno(r, "Failed to chase os-release in image: %m");
1000 else if (r >= 0) {
1001 r = load_env_file_pairs(NULL, path, NULL, &os_release);
1002 if (r < 0)
1003 log_debug_errno(r, "Failed to parse os-release data of %s: %m", i->name);
1004 }
1005
1006 free_and_replace(i->hostname, hostname);
1007 i->machine_id = machine_id;
1008 strv_free_and_replace(i->machine_info, machine_info);
1009 strv_free_and_replace(i->os_release, os_release);
1010
1011 break;
1012 }
1013
1014 case IMAGE_RAW:
1015 case IMAGE_BLOCK: {
1016 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
1017 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
1018
1019 r = loop_device_make_by_path(i->path, O_RDONLY, &d);
1020 if (r < 0)
1021 return r;
1022
1023 r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
1024 if (r < 0)
1025 return r;
1026
1027 r = dissected_image_acquire_metadata(m);
1028 if (r < 0)
1029 return r;
1030
1031 free_and_replace(i->hostname, m->hostname);
1032 i->machine_id = m->machine_id;
1033 strv_free_and_replace(i->machine_info, m->machine_info);
1034 strv_free_and_replace(i->os_release, m->os_release);
1035
1036 break;
1037 }
1038
1039 default:
1040 return -EOPNOTSUPP;
1041 }
1042
1043 i->metadata_valid = true;
1044
1045 return 0;
1046}
1047
30535c16
LP
1048int image_name_lock(const char *name, int operation, LockFile *ret) {
1049 const char *p;
1050
1051 assert(name);
1052 assert(ret);
1053
1054 /* Locks an image name, regardless of the precise path used. */
1055
1056 if (!image_name_is_valid(name))
1057 return -EINVAL;
1058
b6e953f2
LP
1059 if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
1060 *ret = (LockFile) LOCK_FILE_INIT;
1061 return 0;
1062 }
1063
30535c16
LP
1064 if (streq(name, ".host"))
1065 return -EBUSY;
1066
7e7cddb2 1067 mkdir_p("/run/systemd/nspawn/locks", 0700);
63c372cb 1068 p = strjoina("/run/systemd/nspawn/locks/name-", name);
30535c16
LP
1069
1070 return make_lock_file(p, operation, ret);
1071}
1072
1073bool image_name_is_valid(const char *s) {
1074 if (!filename_is_valid(s))
1075 return false;
1076
1077 if (string_has_cc(s, NULL))
1078 return false;
1079
1080 if (!utf8_is_valid(s))
1081 return false;
1082
1083 /* Temporary files for atomically creating new files */
1084 if (startswith(s, ".#"))
1085 return false;
1086
1087 return true;
1088}
1089
cd61c3bf
LP
1090static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
1091 [IMAGE_DIRECTORY] = "directory",
1092 [IMAGE_SUBVOLUME] = "subvolume",
aceac2f0 1093 [IMAGE_RAW] = "raw",
eb38edce 1094 [IMAGE_BLOCK] = "block",
cd61c3bf
LP
1095};
1096
1097DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);