]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/dissect-image.c
Merge pull request #8617 from keszybz/tmpfiles-relax
[thirdparty/systemd.git] / src / shared / dissect-image.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8c1be37e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2016 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <sys/mount.h>
3b925504
LP
22#include <sys/prctl.h>
23#include <sys/wait.h>
8c1be37e 24
dccca82b
LP
25#include "sd-id128.h"
26
8c1be37e 27#include "architecture.h"
18b5886e 28#include "ask-password-api.h"
8c1be37e 29#include "blkid-util.h"
18c528e9 30#include "blockdev-util.h"
3b925504 31#include "copy.h"
294bd454 32#include "crypt-util.h"
3b925504 33#include "def.h"
553e15f2 34#include "device-nodes.h"
8c1be37e 35#include "dissect-image.h"
18b5886e 36#include "fd-util.h"
78ebe980 37#include "fileio.h"
2eedfd2d 38#include "fs-util.h"
8c1be37e 39#include "gpt.h"
78ebe980 40#include "hexdecoct.h"
3b925504
LP
41#include "hostname-util.h"
42#include "id128-util.h"
dcce98a4 43#include "linux-3.13/dm-ioctl.h"
ffc01f06 44#include "missing.h"
8c1be37e
LP
45#include "mount-util.h"
46#include "path-util.h"
3b925504
LP
47#include "process-util.h"
48#include "raw-clone.h"
49#include "signal-util.h"
8c1be37e 50#include "stat-util.h"
18b5886e 51#include "stdio-util.h"
8c1be37e
LP
52#include "string-table.h"
53#include "string-util.h"
2eedfd2d 54#include "strv.h"
8c1be37e 55#include "udev-util.h"
2d3a5a73 56#include "user-util.h"
41488e1f 57#include "xattr-util.h"
8c1be37e 58
c34b75a1 59int probe_filesystem(const char *node, char **ret_fstype) {
7cc84b2c
ZJS
60 /* Try to find device content type and return it in *ret_fstype. If nothing is found,
61 * 0/NULL will be returned. -EUCLEAN will be returned for ambigous results, and an
62 * different error otherwise. */
63
349cc4a5 64#if HAVE_BLKID
18b5886e
LP
65 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
66 const char *fstype;
67 int r;
68
995fa2e5 69 errno = 0;
18b5886e
LP
70 b = blkid_new_probe_from_filename(node);
71 if (!b)
995fa2e5 72 return -errno ?: -ENOMEM;
18b5886e
LP
73
74 blkid_probe_enable_superblocks(b, 1);
75 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
76
77 errno = 0;
78 r = blkid_do_safeprobe(b);
7cc84b2c
ZJS
79 if (r == 1) {
80 log_debug("No type detected on partition %s", node);
18b5886e
LP
81 goto not_found;
82 }
7cc84b2c
ZJS
83 if (r == -2) {
84 log_debug("Results ambiguous for partition %s", node);
85 return -EUCLEAN;
86 }
b382db9f
ZJS
87 if (r != 0)
88 return -errno ?: -EIO;
18b5886e
LP
89
90 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
91
92 if (fstype) {
93 char *t;
94
95 t = strdup(fstype);
96 if (!t)
97 return -ENOMEM;
98
99 *ret_fstype = t;
100 return 1;
101 }
102
103not_found:
104 *ret_fstype = NULL;
105 return 0;
d1c536f5
ZJS
106#else
107 return -EOPNOTSUPP;
a75e27eb 108#endif
d1c536f5 109}
18b5886e 110
cde942f6
JPRV
111/* Detect RPMB and Boot partitions, which are not listed by blkid.
112 * See https://github.com/systemd/systemd/issues/5806. */
113static bool device_is_mmc_special_partition(struct udev_device *d) {
114 const char *sysname = udev_device_get_sysname(d);
115 return (sysname && startswith(sysname, "mmcblk") &&
116 (endswith(sysname, "rpmb") || endswith(sysname, "boot0") || endswith(sysname, "boot1")));
117}
118
4526113f
LP
119int dissect_image(
120 int fd,
121 const void *root_hash,
122 size_t root_hash_size,
123 DissectImageFlags flags,
124 DissectedImage **ret) {
8c1be37e 125
349cc4a5 126#if HAVE_BLKID
4623e8e6 127 sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
8c1be37e
LP
128 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
129 bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
130 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
131 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
132 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
133 _cleanup_udev_unref_ struct udev *udev = NULL;
134 _cleanup_free_ char *generic_node = NULL;
be30ad41 135 sd_id128_t generic_uuid = SD_ID128_NULL;
9b6deb03 136 const char *pttype = NULL;
8c1be37e
LP
137 struct udev_list_entry *first, *item;
138 blkid_partlist pl;
139 int r, generic_nr;
140 struct stat st;
141 unsigned i;
142
143 assert(fd >= 0);
144 assert(ret);
4623e8e6 145 assert(root_hash || root_hash_size == 0);
8c1be37e
LP
146
147 /* Probes a disk image, and returns information about what it found in *ret.
148 *
4623e8e6
LP
149 * Returns -ENOPKG if no suitable partition table or file system could be found.
150 * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */
151
152 if (root_hash) {
153 /* If a root hash is supplied, then we use the root partition that has a UUID that match the first
154 * 128bit of the root hash. And we use the verity partition that has a UUID that match the final
155 * 128bit. */
156
157 if (root_hash_size < sizeof(sd_id128_t))
158 return -EINVAL;
159
160 memcpy(&root_uuid, root_hash, sizeof(sd_id128_t));
161 memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t));
162
163 if (sd_id128_is_null(root_uuid))
164 return -EINVAL;
165 if (sd_id128_is_null(verity_uuid))
166 return -EINVAL;
167 }
8c1be37e
LP
168
169 if (fstat(fd, &st) < 0)
170 return -errno;
171
172 if (!S_ISBLK(st.st_mode))
173 return -ENOTBLK;
174
175 b = blkid_new_probe();
176 if (!b)
177 return -ENOMEM;
178
179 errno = 0;
180 r = blkid_probe_set_device(b, fd, 0, 0);
b382db9f
ZJS
181 if (r != 0)
182 return -errno ?: -ENOMEM;
8c1be37e 183
9b6deb03
LP
184 if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
185 /* Look for file system superblocks, unless we only shall look for GPT partition tables */
186 blkid_probe_enable_superblocks(b, 1);
187 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE);
188 }
189
8c1be37e
LP
190 blkid_probe_enable_partitions(b, 1);
191 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
192
193 errno = 0;
194 r = blkid_do_safeprobe(b);
4c701096 195 if (IN_SET(r, -2, 1)) {
8c1be37e
LP
196 log_debug("Failed to identify any partition table.");
197 return -ENOPKG;
198 }
b382db9f
ZJS
199 if (r != 0)
200 return -errno ?: -EIO;
8c1be37e
LP
201
202 m = new0(DissectedImage, 1);
203 if (!m)
204 return -ENOMEM;
205
e0f9e7bd
LP
206 if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
207 (flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
9b6deb03 208 const char *usage = NULL;
8c1be37e 209
9b6deb03
LP
210 (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
211 if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
212 _cleanup_free_ char *t = NULL, *n = NULL;
213 const char *fstype = NULL;
8c1be37e 214
9b6deb03
LP
215 /* OK, we have found a file system, that's our root partition then. */
216 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
8c1be37e 217
9b6deb03
LP
218 if (fstype) {
219 t = strdup(fstype);
220 if (!t)
221 return -ENOMEM;
222 }
223
224 if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
225 return -ENOMEM;
8c1be37e 226
9b6deb03
LP
227 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
228 .found = true,
229 .rw = true,
230 .partno = -1,
231 .architecture = _ARCHITECTURE_INVALID,
1cc6c93a
YW
232 .fstype = TAKE_PTR(t),
233 .node = TAKE_PTR(n),
9b6deb03 234 };
8c1be37e 235
9b6deb03 236 m->encrypted = streq(fstype, "crypto_LUKS");
18b5886e 237
1cc6c93a 238 *ret = TAKE_PTR(m);
8c1be37e 239
9b6deb03
LP
240 return 0;
241 }
8c1be37e
LP
242 }
243
244 (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
245 if (!pttype)
246 return -ENOPKG;
247
248 is_gpt = streq_ptr(pttype, "gpt");
249 is_mbr = streq_ptr(pttype, "dos");
250
9b6deb03 251 if (!is_gpt && ((flags & DISSECT_IMAGE_GPT_ONLY) || !is_mbr))
8c1be37e
LP
252 return -ENOPKG;
253
254 errno = 0;
255 pl = blkid_probe_get_partitions(b);
b382db9f
ZJS
256 if (!pl)
257 return -errno ?: -ENOMEM;
8c1be37e
LP
258
259 udev = udev_new();
260 if (!udev)
261 return -errno;
262
263 d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
264 if (!d)
265 return -ENOMEM;
266
267 for (i = 0;; i++) {
268 int n, z;
269
270 if (i >= 10) {
271 log_debug("Kernel partitions never appeared.");
272 return -ENXIO;
273 }
274
275 e = udev_enumerate_new(udev);
276 if (!e)
277 return -errno;
278
279 r = udev_enumerate_add_match_parent(e, d);
280 if (r < 0)
281 return r;
282
283 r = udev_enumerate_scan_devices(e);
284 if (r < 0)
285 return r;
286
287 /* Count the partitions enumerated by the kernel */
288 n = 0;
289 first = udev_enumerate_get_list_entry(e);
cde942f6
JPRV
290 udev_list_entry_foreach(item, first) {
291 _cleanup_udev_device_unref_ struct udev_device *q;
292
293 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
294 if (!q)
295 return -errno;
296
297 if (device_is_mmc_special_partition(q))
298 continue;
8c1be37e 299 n++;
cde942f6 300 }
8c1be37e
LP
301
302 /* Count the partitions enumerated by blkid */
303 z = blkid_partlist_numof_partitions(pl);
304 if (n == z + 1)
305 break;
306 if (n > z + 1) {
307 log_debug("blkid and kernel partition list do not match.");
308 return -EIO;
309 }
310 if (n < z + 1) {
759aaedc 311 unsigned j = 0;
8c1be37e
LP
312
313 /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
314 * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
315 * synchronous call that waits until probing is complete. */
316
759aaedc
LP
317 for (;;) {
318 if (j++ > 20)
319 return -EBUSY;
8c1be37e 320
759aaedc 321 if (ioctl(fd, BLKRRPART, 0) < 0) {
8c1be37e 322 r = -errno;
759aaedc
LP
323
324 if (r == -EINVAL) {
325 struct loop_info64 info;
326
327 /* If we are running on a loop device that has partition scanning off,
328 * return an explicit recognizable error about this, so that callers
329 * can generate a proper message explaining the situation. */
330
331 if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
332 log_debug("Device is loop device and partition scanning is off!");
333 return -EPROTONOSUPPORT;
334 }
335 }
336 if (r != -EBUSY)
337 return r;
338 } else
8c1be37e
LP
339 break;
340
341 /* If something else has the device open, such as an udev rule, the ioctl will return
342 * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a
343 * bit, and try again.
344 *
345 * This is really something they should fix in the kernel! */
346
759aaedc 347 (void) usleep(50 * USEC_PER_MSEC);
8c1be37e 348 }
8c1be37e
LP
349 }
350
351 e = udev_enumerate_unref(e);
352 }
353
354 first = udev_enumerate_get_list_entry(e);
355 udev_list_entry_foreach(item, first) {
356 _cleanup_udev_device_unref_ struct udev_device *q;
9b6deb03 357 unsigned long long pflags;
8c1be37e 358 blkid_partition pp;
cde942f6 359 const char *node;
8c1be37e
LP
360 dev_t qn;
361 int nr;
362
363 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
364 if (!q)
365 return -errno;
366
367 qn = udev_device_get_devnum(q);
368 if (major(qn) == 0)
369 continue;
370
371 if (st.st_rdev == qn)
372 continue;
373
cde942f6 374 if (device_is_mmc_special_partition(q))
7be1420f
LP
375 continue;
376
8c1be37e
LP
377 node = udev_device_get_devnode(q);
378 if (!node)
379 continue;
380
381 pp = blkid_partlist_devno_to_partition(pl, qn);
382 if (!pp)
383 continue;
384
9b6deb03 385 pflags = blkid_partition_get_flags(pp);
8c1be37e
LP
386
387 nr = blkid_partition_get_partno(pp);
388 if (nr < 0)
389 continue;
390
391 if (is_gpt) {
392 int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID;
4623e8e6
LP
393 const char *stype, *sid, *fstype = NULL;
394 sd_id128_t type_id, id;
8c1be37e
LP
395 bool rw = true;
396
4623e8e6
LP
397 sid = blkid_partition_get_uuid(pp);
398 if (!sid)
399 continue;
400 if (sd_id128_from_string(sid, &id) < 0)
401 continue;
402
8c1be37e
LP
403 stype = blkid_partition_get_type_string(pp);
404 if (!stype)
405 continue;
8c1be37e
LP
406 if (sd_id128_from_string(stype, &type_id) < 0)
407 continue;
408
409 if (sd_id128_equal(type_id, GPT_HOME)) {
a48dd347
LP
410
411 if (pflags & GPT_FLAG_NO_AUTO)
412 continue;
413
8c1be37e 414 designator = PARTITION_HOME;
9b6deb03 415 rw = !(pflags & GPT_FLAG_READ_ONLY);
8c1be37e 416 } else if (sd_id128_equal(type_id, GPT_SRV)) {
a48dd347
LP
417
418 if (pflags & GPT_FLAG_NO_AUTO)
419 continue;
420
8c1be37e 421 designator = PARTITION_SRV;
9b6deb03 422 rw = !(pflags & GPT_FLAG_READ_ONLY);
8c1be37e 423 } else if (sd_id128_equal(type_id, GPT_ESP)) {
a48dd347
LP
424
425 /* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined
426 * there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the
427 * UEFI spec (See "12.3.3 Number and Location of System Partitions"). */
428
429 if (pflags & GPT_FLAG_NO_BLOCK_IO_PROTOCOL)
430 continue;
431
8c1be37e
LP
432 designator = PARTITION_ESP;
433 fstype = "vfat";
434 }
435#ifdef GPT_ROOT_NATIVE
436 else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
4623e8e6 437
a48dd347
LP
438 if (pflags & GPT_FLAG_NO_AUTO)
439 continue;
440
4623e8e6
LP
441 /* If a root ID is specified, ignore everything but the root id */
442 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
443 continue;
444
8c1be37e
LP
445 designator = PARTITION_ROOT;
446 architecture = native_architecture();
9b6deb03 447 rw = !(pflags & GPT_FLAG_READ_ONLY);
4f8b86e3 448 } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
4623e8e6 449
a48dd347
LP
450 if (pflags & GPT_FLAG_NO_AUTO)
451 continue;
452
4623e8e6
LP
453 m->can_verity = true;
454
455 /* Ignore verity unless a root hash is specified */
456 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
457 continue;
458
459 designator = PARTITION_ROOT_VERITY;
460 fstype = "DM_verity_hash";
461 architecture = native_architecture();
462 rw = false;
463 }
464#endif
8c1be37e
LP
465#ifdef GPT_ROOT_SECONDARY
466 else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) {
4623e8e6 467
a48dd347
LP
468 if (pflags & GPT_FLAG_NO_AUTO)
469 continue;
470
4623e8e6
LP
471 /* If a root ID is specified, ignore everything but the root id */
472 if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
473 continue;
474
8c1be37e
LP
475 designator = PARTITION_ROOT_SECONDARY;
476 architecture = SECONDARY_ARCHITECTURE;
9b6deb03 477 rw = !(pflags & GPT_FLAG_READ_ONLY);
4f8b86e3 478 } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
a48dd347
LP
479
480 if (pflags & GPT_FLAG_NO_AUTO)
481 continue;
482
4623e8e6
LP
483 m->can_verity = true;
484
485 /* Ignore verity unless root has is specified */
486 if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id))
487 continue;
488
489 designator = PARTITION_ROOT_SECONDARY_VERITY;
490 fstype = "DM_verity_hash";
491 architecture = SECONDARY_ARCHITECTURE;
492 rw = false;
493 }
8c1be37e
LP
494#endif
495 else if (sd_id128_equal(type_id, GPT_SWAP)) {
a48dd347
LP
496
497 if (pflags & GPT_FLAG_NO_AUTO)
498 continue;
499
8c1be37e
LP
500 designator = PARTITION_SWAP;
501 fstype = "swap";
502 } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) {
503
a48dd347
LP
504 if (pflags & GPT_FLAG_NO_AUTO)
505 continue;
506
8c1be37e
LP
507 if (generic_node)
508 multiple_generic = true;
509 else {
510 generic_nr = nr;
9b6deb03 511 generic_rw = !(pflags & GPT_FLAG_READ_ONLY);
be30ad41 512 generic_uuid = id;
8c1be37e
LP
513 generic_node = strdup(node);
514 if (!generic_node)
515 return -ENOMEM;
516 }
517 }
518
519 if (designator != _PARTITION_DESIGNATOR_INVALID) {
520 _cleanup_free_ char *t = NULL, *n = NULL;
521
522 /* First one wins */
523 if (m->partitions[designator].found)
524 continue;
525
526 if (fstype) {
527 t = strdup(fstype);
528 if (!t)
529 return -ENOMEM;
530 }
531
532 n = strdup(node);
533 if (!n)
534 return -ENOMEM;
535
536 m->partitions[designator] = (DissectedPartition) {
537 .found = true,
538 .partno = nr,
539 .rw = rw,
540 .architecture = architecture,
1cc6c93a
YW
541 .node = TAKE_PTR(n),
542 .fstype = TAKE_PTR(t),
be30ad41 543 .uuid = id,
8c1be37e 544 };
8c1be37e
LP
545 }
546
547 } else if (is_mbr) {
548
9b6deb03 549 if (pflags != 0x80) /* Bootable flag */
8c1be37e
LP
550 continue;
551
552 if (blkid_partition_get_type(pp) != 0x83) /* Linux partition */
553 continue;
554
555 if (generic_node)
556 multiple_generic = true;
557 else {
558 generic_nr = nr;
559 generic_rw = true;
560 generic_node = strdup(node);
561 if (!generic_node)
562 return -ENOMEM;
563 }
564 }
565 }
566
567 if (!m->partitions[PARTITION_ROOT].found) {
568 /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not
569 * either, then check if there's a single generic one, and use that. */
570
4623e8e6 571 if (m->partitions[PARTITION_ROOT_VERITY].found)
e0f9e7bd 572 return -EADDRNOTAVAIL;
4623e8e6 573
8c1be37e
LP
574 if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
575 m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
576 zero(m->partitions[PARTITION_ROOT_SECONDARY]);
4623e8e6
LP
577
578 m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
579 zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
580
e0f9e7bd
LP
581 } else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
582
583 /* If the root has was set, then we won't fallback to a generic node, because the root hash
584 * decides */
585 if (root_hash)
586 return -EADDRNOTAVAIL;
8c1be37e 587
e0f9e7bd
LP
588 /* If we didn't find a generic node, then we can't fix this up either */
589 if (!generic_node)
590 return -ENXIO;
591
592 /* If we didn't find a properly marked root partition, but we did find a single suitable
593 * generic Linux partition, then use this as root partition, if the caller asked for it. */
8c1be37e
LP
594 if (multiple_generic)
595 return -ENOTUNIQ;
596
597 m->partitions[PARTITION_ROOT] = (DissectedPartition) {
598 .found = true,
599 .rw = generic_rw,
600 .partno = generic_nr,
601 .architecture = _ARCHITECTURE_INVALID,
1cc6c93a 602 .node = TAKE_PTR(generic_node),
be30ad41 603 .uuid = generic_uuid,
8c1be37e 604 };
e0f9e7bd 605 }
8c1be37e
LP
606 }
607
4623e8e6 608 if (root_hash) {
e0f9e7bd 609 if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
4623e8e6
LP
610 return -EADDRNOTAVAIL;
611
612 /* If we found the primary root with the hash, then we definitely want to suppress any secondary root
613 * (which would be weird, after all the root hash should only be assigned to one pair of
614 * partitions... */
615 m->partitions[PARTITION_ROOT_SECONDARY].found = false;
616 m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false;
617
618 /* If we found a verity setup, then the root partition is necessarily read-only. */
619 m->partitions[PARTITION_ROOT].rw = false;
620
621 m->verity = true;
622 }
623
18b5886e
LP
624 blkid_free_probe(b);
625 b = NULL;
626
8c1be37e
LP
627 /* Fill in file system types if we don't know them yet. */
628 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
18b5886e 629 DissectedPartition *p = m->partitions + i;
8c1be37e 630
18b5886e 631 if (!p->found)
8c1be37e
LP
632 continue;
633
18b5886e
LP
634 if (!p->fstype && p->node) {
635 r = probe_filesystem(p->node, &p->fstype);
7cc84b2c 636 if (r < 0 && r != -EUCLEAN)
18b5886e 637 return r;
8c1be37e
LP
638 }
639
18b5886e
LP
640 if (streq_ptr(p->fstype, "crypto_LUKS"))
641 m->encrypted = true;
896f937f
LP
642
643 if (p->fstype && fstype_is_ro(p->fstype))
644 p->rw = false;
8c1be37e
LP
645 }
646
1cc6c93a 647 *ret = TAKE_PTR(m);
8c1be37e
LP
648
649 return 0;
650#else
651 return -EOPNOTSUPP;
652#endif
653}
654
655DissectedImage* dissected_image_unref(DissectedImage *m) {
656 unsigned i;
657
658 if (!m)
659 return NULL;
660
661 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
662 free(m->partitions[i].fstype);
663 free(m->partitions[i].node);
18b5886e
LP
664 free(m->partitions[i].decrypted_fstype);
665 free(m->partitions[i].decrypted_node);
8c1be37e
LP
666 }
667
3b925504
LP
668 free(m->hostname);
669 strv_free(m->machine_info);
670 strv_free(m->os_release);
671
5fecf46d 672 return mfree(m);
8c1be37e
LP
673}
674
18b5886e 675static int is_loop_device(const char *path) {
553e15f2 676 char s[SYS_BLOCK_PATH_MAX("/../loop/")];
18b5886e
LP
677 struct stat st;
678
679 assert(path);
680
681 if (stat(path, &st) < 0)
682 return -errno;
683
684 if (!S_ISBLK(st.st_mode))
685 return -ENOTBLK;
686
553e15f2 687 xsprintf_sys_block_path(s, "/loop/", st.st_dev);
18b5886e
LP
688 if (access(s, F_OK) < 0) {
689 if (errno != ENOENT)
690 return -errno;
691
692 /* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
553e15f2 693 xsprintf_sys_block_path(s, "/../loop/", st.st_dev);
18b5886e
LP
694 if (access(s, F_OK) < 0)
695 return errno == ENOENT ? false : -errno;
696 }
697
698 return true;
699}
700
701static int mount_partition(
702 DissectedPartition *m,
703 const char *where,
704 const char *directory,
2d3a5a73 705 uid_t uid_shift,
18b5886e
LP
706 DissectImageFlags flags) {
707
2d3a5a73
LP
708 _cleanup_free_ char *chased = NULL, *options = NULL;
709 const char *p, *node, *fstype;
8c1be37e 710 bool rw;
2eedfd2d 711 int r;
8c1be37e
LP
712
713 assert(m);
714 assert(where);
715
18b5886e
LP
716 node = m->decrypted_node ?: m->node;
717 fstype = m->decrypted_fstype ?: m->fstype;
718
719 if (!m->found || !node || !fstype)
8c1be37e
LP
720 return 0;
721
18b5886e
LP
722 /* Stacked encryption? Yuck */
723 if (streq_ptr(fstype, "crypto_LUKS"))
724 return -ELOOP;
725
726 rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
8c1be37e 727
2eedfd2d
LP
728 if (directory) {
729 r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased);
730 if (r < 0)
731 return r;
732
733 p = chased;
734 } else
8c1be37e
LP
735 p = where;
736
18b5886e 737 /* If requested, turn on discard support. */
154d2269 738 if (fstype_can_discard(fstype) &&
18b5886e 739 ((flags & DISSECT_IMAGE_DISCARD) ||
2d3a5a73
LP
740 ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node)))) {
741 options = strdup("discard");
742 if (!options)
743 return -ENOMEM;
744 }
745
746 if (uid_is_valid(uid_shift) && uid_shift != 0 && fstype_can_uid_gid(fstype)) {
747 _cleanup_free_ char *uid_option = NULL;
748
749 if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
750 return -ENOMEM;
751
752 if (!strextend_with_separator(&options, ",", uid_option, NULL))
753 return -ENOMEM;
754 }
8c1be37e 755
18b5886e 756 return mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
8c1be37e
LP
757}
758
2d3a5a73 759int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
8c1be37e
LP
760 int r;
761
762 assert(m);
763 assert(where);
764
765 if (!m->partitions[PARTITION_ROOT].found)
766 return -ENXIO;
767
2d3a5a73
LP
768 if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
769 r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, flags);
770 if (r < 0)
771 return r;
772 }
773
774 if ((flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY))
775 return 0;
8c1be37e 776
2d3a5a73 777 r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
8c1be37e
LP
778 if (r < 0)
779 return r;
780
2d3a5a73 781 r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", uid_shift, flags);
8c1be37e
LP
782 if (r < 0)
783 return r;
784
785 if (m->partitions[PARTITION_ESP].found) {
2eedfd2d 786 const char *mp;
8c1be37e
LP
787
788 /* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
789
2eedfd2d
LP
790 FOREACH_STRING(mp, "/efi", "/boot") {
791 _cleanup_free_ char *p = NULL;
792
793 r = chase_symlinks(mp, where, CHASE_PREFIX_ROOT, &p);
8c1be37e 794 if (r < 0)
2eedfd2d
LP
795 continue;
796
797 r = dir_is_empty(p);
798 if (r > 0) {
2d3a5a73 799 r = mount_partition(m->partitions + PARTITION_ESP, where, mp, uid_shift, flags);
2eedfd2d
LP
800 if (r < 0)
801 return r;
802 }
8c1be37e
LP
803 }
804 }
805
806 return 0;
807}
808
349cc4a5 809#if HAVE_LIBCRYPTSETUP
18b5886e
LP
810typedef struct DecryptedPartition {
811 struct crypt_device *device;
812 char *name;
813 bool relinquished;
814} DecryptedPartition;
815
816struct DecryptedImage {
817 DecryptedPartition *decrypted;
818 size_t n_decrypted;
819 size_t n_allocated;
820};
821#endif
822
823DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
349cc4a5 824#if HAVE_LIBCRYPTSETUP
18b5886e
LP
825 size_t i;
826 int r;
827
828 if (!d)
829 return NULL;
830
831 for (i = 0; i < d->n_decrypted; i++) {
832 DecryptedPartition *p = d->decrypted + i;
833
834 if (p->device && p->name && !p->relinquished) {
835 r = crypt_deactivate(p->device, p->name);
836 if (r < 0)
837 log_debug_errno(r, "Failed to deactivate encrypted partition %s", p->name);
838 }
839
840 if (p->device)
841 crypt_free(p->device);
842 free(p->name);
843 }
844
845 free(d);
846#endif
847 return NULL;
848}
849
349cc4a5 850#if HAVE_LIBCRYPTSETUP
4623e8e6
LP
851
852static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) {
853 _cleanup_free_ char *name = NULL, *node = NULL;
854 const char *base;
855
856 assert(original_node);
857 assert(suffix);
858 assert(ret_name);
859 assert(ret_node);
860
861 base = strrchr(original_node, '/');
862 if (!base)
863 return -EINVAL;
864 base++;
865 if (isempty(base))
866 return -EINVAL;
867
868 name = strjoin(base, suffix);
869 if (!name)
870 return -ENOMEM;
871 if (!filename_is_valid(name))
872 return -EINVAL;
873
874 node = strjoin(crypt_get_dir(), "/", name);
875 if (!node)
876 return -ENOMEM;
877
1cc6c93a
YW
878 *ret_name = TAKE_PTR(name);
879 *ret_node = TAKE_PTR(node);
4623e8e6 880
4623e8e6
LP
881 return 0;
882}
883
18b5886e
LP
884static int decrypt_partition(
885 DissectedPartition *m,
886 const char *passphrase,
887 DissectImageFlags flags,
888 DecryptedImage *d) {
889
890 _cleanup_free_ char *node = NULL, *name = NULL;
294bd454 891 _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
18b5886e
LP
892 int r;
893
894 assert(m);
895 assert(d);
896
897 if (!m->found || !m->node || !m->fstype)
898 return 0;
899
900 if (!streq(m->fstype, "crypto_LUKS"))
901 return 0;
902
bdd73ac5
ZJS
903 if (!passphrase)
904 return -ENOKEY;
905
4623e8e6
LP
906 r = make_dm_name_and_node(m->node, "-decrypted", &name, &node);
907 if (r < 0)
908 return r;
18b5886e
LP
909
910 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
911 return -ENOMEM;
912
913 r = crypt_init(&cd, m->node);
914 if (r < 0)
715cbb81 915 return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
18b5886e 916
dd59868b 917 r = crypt_load(cd, CRYPT_LUKS, NULL);
294bd454
ZJS
918 if (r < 0)
919 return log_debug_errno(r, "Failed to load LUKS metadata: %m");
18b5886e
LP
920
921 r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
922 ((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
923 ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
294bd454 924 if (r < 0) {
715cbb81 925 log_debug_errno(r, "Failed to activate LUKS device: %m");
294bd454 926 return r == -EPERM ? -EKEYREJECTED : r;
18b5886e 927 }
18b5886e 928
1cc6c93a
YW
929 d->decrypted[d->n_decrypted].name = TAKE_PTR(name);
930 d->decrypted[d->n_decrypted].device = TAKE_PTR(cd);
18b5886e
LP
931 d->n_decrypted++;
932
1cc6c93a 933 m->decrypted_node = TAKE_PTR(node);
18b5886e
LP
934
935 return 0;
4623e8e6
LP
936}
937
938static int verity_partition(
939 DissectedPartition *m,
940 DissectedPartition *v,
941 const void *root_hash,
942 size_t root_hash_size,
943 DissectImageFlags flags,
944 DecryptedImage *d) {
945
946 _cleanup_free_ char *node = NULL, *name = NULL;
294bd454 947 _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
4623e8e6
LP
948 int r;
949
950 assert(m);
951 assert(v);
952
953 if (!root_hash)
954 return 0;
955
956 if (!m->found || !m->node || !m->fstype)
957 return 0;
958 if (!v->found || !v->node || !v->fstype)
959 return 0;
960
961 if (!streq(v->fstype, "DM_verity_hash"))
962 return 0;
963
964 r = make_dm_name_and_node(m->node, "-verity", &name, &node);
965 if (r < 0)
966 return r;
967
968 if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
969 return -ENOMEM;
970
971 r = crypt_init(&cd, v->node);
972 if (r < 0)
973 return r;
974
975 r = crypt_load(cd, CRYPT_VERITY, NULL);
976 if (r < 0)
294bd454 977 return r;
4623e8e6
LP
978
979 r = crypt_set_data_device(cd, m->node);
980 if (r < 0)
294bd454 981 return r;
4623e8e6
LP
982
983 r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
984 if (r < 0)
294bd454 985 return r;
4623e8e6 986
1cc6c93a
YW
987 d->decrypted[d->n_decrypted].name = TAKE_PTR(name);
988 d->decrypted[d->n_decrypted].device = TAKE_PTR(cd);
4623e8e6
LP
989 d->n_decrypted++;
990
1cc6c93a 991 m->decrypted_node = TAKE_PTR(node);
4623e8e6
LP
992
993 return 0;
18b5886e
LP
994}
995#endif
996
997int dissected_image_decrypt(
998 DissectedImage *m,
999 const char *passphrase,
4623e8e6
LP
1000 const void *root_hash,
1001 size_t root_hash_size,
18b5886e
LP
1002 DissectImageFlags flags,
1003 DecryptedImage **ret) {
1004
349cc4a5 1005#if HAVE_LIBCRYPTSETUP
49b5b3b4 1006 _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
18b5886e
LP
1007 unsigned i;
1008 int r;
1009#endif
1010
1011 assert(m);
4623e8e6 1012 assert(root_hash || root_hash_size == 0);
18b5886e
LP
1013
1014 /* Returns:
1015 *
1016 * = 0 → There was nothing to decrypt
1017 * > 0 → Decrypted successfully
d1c536f5 1018 * -ENOKEY → There's something to decrypt but no key was supplied
18b5886e
LP
1019 * -EKEYREJECTED → Passed key was not correct
1020 */
1021
4623e8e6
LP
1022 if (root_hash && root_hash_size < sizeof(sd_id128_t))
1023 return -EINVAL;
1024
1025 if (!m->encrypted && !m->verity) {
18b5886e
LP
1026 *ret = NULL;
1027 return 0;
1028 }
1029
349cc4a5 1030#if HAVE_LIBCRYPTSETUP
18b5886e
LP
1031 d = new0(DecryptedImage, 1);
1032 if (!d)
1033 return -ENOMEM;
1034
1035 for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
1036 DissectedPartition *p = m->partitions + i;
4623e8e6 1037 int k;
18b5886e
LP
1038
1039 if (!p->found)
1040 continue;
1041
1042 r = decrypt_partition(p, passphrase, flags, d);
1043 if (r < 0)
1044 return r;
1045
4623e8e6
LP
1046 k = PARTITION_VERITY_OF(i);
1047 if (k >= 0) {
1048 r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d);
1049 if (r < 0)
1050 return r;
1051 }
1052
18b5886e
LP
1053 if (!p->decrypted_fstype && p->decrypted_node) {
1054 r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype);
7cc84b2c 1055 if (r < 0 && r != -EUCLEAN)
18b5886e
LP
1056 return r;
1057 }
1058 }
1059
1cc6c93a 1060 *ret = TAKE_PTR(d);
18b5886e
LP
1061
1062 return 1;
1063#else
1064 return -EOPNOTSUPP;
1065#endif
1066}
1067
1068int dissected_image_decrypt_interactively(
1069 DissectedImage *m,
1070 const char *passphrase,
4623e8e6
LP
1071 const void *root_hash,
1072 size_t root_hash_size,
18b5886e
LP
1073 DissectImageFlags flags,
1074 DecryptedImage **ret) {
1075
1076 _cleanup_strv_free_erase_ char **z = NULL;
1077 int n = 3, r;
1078
1079 if (passphrase)
1080 n--;
1081
1082 for (;;) {
4623e8e6 1083 r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret);
18b5886e
LP
1084 if (r >= 0)
1085 return r;
1086 if (r == -EKEYREJECTED)
1087 log_error_errno(r, "Incorrect passphrase, try again!");
1088 else if (r != -ENOKEY) {
1089 log_error_errno(r, "Failed to decrypt image: %m");
1090 return r;
1091 }
1092
1093 if (--n < 0) {
1094 log_error("Too many retries.");
1095 return -EKEYREJECTED;
1096 }
1097
1098 z = strv_free(z);
1099
1100 r = ask_password_auto("Please enter image passphrase!", NULL, "dissect", "dissect", USEC_INFINITY, 0, &z);
1101 if (r < 0)
1102 return log_error_errno(r, "Failed to query for passphrase: %m");
1103
1104 passphrase = z[0];
1105 }
1106}
1107
349cc4a5 1108#if HAVE_LIBCRYPTSETUP
18b5886e
LP
1109static int deferred_remove(DecryptedPartition *p) {
1110
1111 struct dm_ioctl dm = {
1112 .version = {
1113 DM_VERSION_MAJOR,
1114 DM_VERSION_MINOR,
1115 DM_VERSION_PATCHLEVEL
1116 },
1117 .data_size = sizeof(dm),
1118 .flags = DM_DEFERRED_REMOVE,
1119 };
1120
1121 _cleanup_close_ int fd = -1;
1122
1123 assert(p);
1124
1125 /* Unfortunately, libcryptsetup doesn't provide a proper API for this, hence call the ioctl() directly. */
1126
1127 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
1128 if (fd < 0)
1129 return -errno;
1130
1131 strncpy(dm.name, p->name, sizeof(dm.name));
1132
1133 if (ioctl(fd, DM_DEV_REMOVE, &dm))
1134 return -errno;
1135
1136 return 0;
1137}
1138#endif
1139
1140int decrypted_image_relinquish(DecryptedImage *d) {
1141
349cc4a5 1142#if HAVE_LIBCRYPTSETUP
18b5886e
LP
1143 size_t i;
1144 int r;
1145#endif
1146
1147 assert(d);
1148
1149 /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
1150 * that we don't clean it up ourselves either anymore */
1151
349cc4a5 1152#if HAVE_LIBCRYPTSETUP
18b5886e
LP
1153 for (i = 0; i < d->n_decrypted; i++) {
1154 DecryptedPartition *p = d->decrypted + i;
1155
1156 if (p->relinquished)
1157 continue;
1158
1159 r = deferred_remove(p);
1160 if (r < 0)
1161 return log_debug_errno(r, "Failed to mark %s for auto-removal: %m", p->name);
1162
1163 p->relinquished = true;
1164 }
1165#endif
1166
1167 return 0;
1168}
1169
78ebe980
LP
1170int root_hash_load(const char *image, void **ret, size_t *ret_size) {
1171 _cleanup_free_ char *text = NULL;
1172 _cleanup_free_ void *k = NULL;
78ebe980
LP
1173 size_t l;
1174 int r;
1175
1176 assert(image);
1177 assert(ret);
1178 assert(ret_size);
1179
1180 if (is_device_path(image)) {
1181 /* If we are asked to load the root hash for a device node, exit early */
1182 *ret = NULL;
1183 *ret_size = 0;
1184 return 0;
1185 }
1186
41488e1f
LP
1187 r = getxattr_malloc(image, "user.verity.roothash", &text, true);
1188 if (r < 0) {
1189 char *fn, *e, *n;
78ebe980 1190
41488e1f
LP
1191 if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
1192 return r;
78ebe980 1193
fbd0b64f 1194 fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
41488e1f
LP
1195 n = stpcpy(fn, image);
1196 e = endswith(fn, ".raw");
1197 if (e)
1198 n = e;
1199
1200 strcpy(n, ".roothash");
1201
1202 r = read_one_line_file(fn, &text);
1203 if (r == -ENOENT) {
1204 *ret = NULL;
1205 *ret_size = 0;
1206 return 0;
1207 }
1208 if (r < 0)
1209 return r;
78ebe980 1210 }
78ebe980
LP
1211
1212 r = unhexmem(text, strlen(text), &k, &l);
1213 if (r < 0)
1214 return r;
1215 if (l < sizeof(sd_id128_t))
1216 return -EINVAL;
1217
1cc6c93a 1218 *ret = TAKE_PTR(k);
78ebe980
LP
1219 *ret_size = l;
1220
78ebe980
LP
1221 return 1;
1222}
1223
3b925504
LP
1224int dissected_image_acquire_metadata(DissectedImage *m) {
1225
1226 enum {
1227 META_HOSTNAME,
1228 META_MACHINE_ID,
1229 META_MACHINE_INFO,
1230 META_OS_RELEASE,
1231 _META_MAX,
1232 };
1233
1234 static const char *const paths[_META_MAX] = {
1235 [META_HOSTNAME] = "/etc/hostname\0",
1236 [META_MACHINE_ID] = "/etc/machine-id\0",
1237 [META_MACHINE_INFO] = "/etc/machine-info\0",
1238 [META_OS_RELEASE] = "/etc/os-release\0/usr/lib/os-release\0",
1239 };
1240
1241 _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
1242 _cleanup_(rmdir_and_freep) char *t = NULL;
1243 _cleanup_(sigkill_waitp) pid_t child = 0;
1244 sd_id128_t machine_id = SD_ID128_NULL;
1245 _cleanup_free_ char *hostname = NULL;
1246 unsigned n_meta_initialized = 0, k;
1247 int fds[2 * _META_MAX], r;
3b925504
LP
1248
1249 BLOCK_SIGNALS(SIGCHLD);
1250
1251 assert(m);
1252
1253 for (; n_meta_initialized < _META_MAX; n_meta_initialized ++)
1254 if (pipe2(fds + 2*n_meta_initialized, O_CLOEXEC) < 0) {
1255 r = -errno;
1256 goto finish;
1257 }
1258
1259 r = mkdtemp_malloc("/tmp/dissect-XXXXXX", &t);
1260 if (r < 0)
1261 goto finish;
1262
be39f6ee
LP
1263 r = safe_fork("(sd-dissect)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_NEW_MOUNTNS, &child);
1264 if (r < 0)
3b925504 1265 goto finish;
be39f6ee 1266 if (r == 0) {
3b925504
LP
1267 /* Make sure we never propagate to the host */
1268 if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
1269 _exit(EXIT_FAILURE);
1270
2d3a5a73 1271 r = dissected_image_mount(m, t, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
3b925504
LP
1272 if (r < 0)
1273 _exit(EXIT_FAILURE);
1274
1275 for (k = 0; k < _META_MAX; k++) {
1276 _cleanup_close_ int fd = -1;
1277 const char *p;
1278
1279 fds[2*k] = safe_close(fds[2*k]);
1280
1281 NULSTR_FOREACH(p, paths[k]) {
36952d19 1282 fd = chase_symlinks_and_open(p, t, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
3b925504
LP
1283 if (fd >= 0)
1284 break;
1285 }
36952d19
LP
1286 if (fd < 0) {
1287 log_debug_errno(fd, "Failed to read %s file of image, ignoring: %m", paths[k]);
3b925504 1288 continue;
36952d19 1289 }
3b925504
LP
1290
1291 r = copy_bytes(fd, fds[2*k+1], (uint64_t) -1, 0);
1292 if (r < 0)
1293 _exit(EXIT_FAILURE);
1294
1295 fds[2*k+1] = safe_close(fds[2*k+1]);
1296 }
1297
1298 _exit(EXIT_SUCCESS);
1299 }
1300
1301 for (k = 0; k < _META_MAX; k++) {
1302 _cleanup_fclose_ FILE *f = NULL;
1303
1304 fds[2*k+1] = safe_close(fds[2*k+1]);
1305
1306 f = fdopen(fds[2*k], "re");
1307 if (!f) {
1308 r = -errno;
1309 goto finish;
1310 }
1311
1312 fds[2*k] = -1;
1313
1314 switch (k) {
1315
1316 case META_HOSTNAME:
1317 r = read_etc_hostname_stream(f, &hostname);
1318 if (r < 0)
1319 log_debug_errno(r, "Failed to read /etc/hostname: %m");
1320
1321 break;
1322
1323 case META_MACHINE_ID: {
1324 _cleanup_free_ char *line = NULL;
1325
1326 r = read_line(f, LONG_LINE_MAX, &line);
1327 if (r < 0)
1328 log_debug_errno(r, "Failed to read /etc/machine-id: %m");
1329 else if (r == 33) {
1330 r = sd_id128_from_string(line, &machine_id);
1331 if (r < 0)
1332 log_debug_errno(r, "Image contains invalid /etc/machine-id: %s", line);
1333 } else if (r == 0)
1334 log_debug("/etc/machine-id file is empty.");
1335 else
1336 log_debug("/etc/machine-id has unexpected length %i.", r);
1337
1338 break;
1339 }
1340
1341 case META_MACHINE_INFO:
1342 r = load_env_file_pairs(f, "machine-info", NULL, &machine_info);
1343 if (r < 0)
1344 log_debug_errno(r, "Failed to read /etc/machine-info: %m");
1345
1346 break;
1347
1348 case META_OS_RELEASE:
1349 r = load_env_file_pairs(f, "os-release", NULL, &os_release);
1350 if (r < 0)
1351 log_debug_errno(r, "Failed to read OS release file: %m");
1352
1353 break;
1354 }
1355 }
1356
2e87a1fd 1357 r = wait_for_terminate_and_check("(sd-dissect)", child, 0);
3b925504 1358 child = 0;
2e87a1fd 1359 if (r < 0)
3b925504 1360 goto finish;
2e87a1fd
LP
1361 if (r != EXIT_SUCCESS)
1362 return -EPROTO;
3b925504
LP
1363
1364 free_and_replace(m->hostname, hostname);
1365 m->machine_id = machine_id;
1366 strv_free_and_replace(m->machine_info, machine_info);
1367 strv_free_and_replace(m->os_release, os_release);
1368
1369finish:
1370 for (k = 0; k < n_meta_initialized; k++)
1371 safe_close_pair(fds + 2*k);
1372
1373 return r;
1374}
1375
4526113f
LP
1376int dissect_image_and_warn(
1377 int fd,
1378 const char *name,
1379 const void *root_hash,
1380 size_t root_hash_size,
1381 DissectImageFlags flags,
1382 DissectedImage **ret) {
1383
1384 _cleanup_free_ char *buffer = NULL;
1385 int r;
1386
1387 if (!name) {
1388 r = fd_get_path(fd, &buffer);
1389 if (r < 0)
1390 return r;
1391
1392 name = buffer;
1393 }
1394
1395 r = dissect_image(fd, root_hash, root_hash_size, flags, ret);
1396
1397 switch (r) {
1398
1399 case -EOPNOTSUPP:
1400 return log_error_errno(r, "Dissecting images is not supported, compiled without blkid support.");
1401
1402 case -ENOPKG:
1403 return log_error_errno(r, "Couldn't identify a suitable partition table or file system in '%s'.", name);
1404
1405 case -EADDRNOTAVAIL:
1406 return log_error_errno(r, "No root partition for specified root hash found in '%s'.", name);
1407
1408 case -ENOTUNIQ:
1409 return log_error_errno(r, "Multiple suitable root partitions found in image '%s'.", name);
1410
1411 case -ENXIO:
1412 return log_error_errno(r, "No suitable root partition found in image '%s'.", name);
1413
1414 case -EPROTONOSUPPORT:
1415 return log_error_errno(r, "Device '%s' is loopback block device with partition scanning turned off, please turn it on.", name);
1416
1417 default:
1418 if (r < 0)
1419 return log_error_errno(r, "Failed to dissect image '%s': %m", name);
1420
1421 return r;
1422 }
1423}
1424
8c1be37e
LP
1425static const char *const partition_designator_table[] = {
1426 [PARTITION_ROOT] = "root",
1427 [PARTITION_ROOT_SECONDARY] = "root-secondary",
1428 [PARTITION_HOME] = "home",
1429 [PARTITION_SRV] = "srv",
1430 [PARTITION_ESP] = "esp",
1431 [PARTITION_SWAP] = "swap",
4623e8e6
LP
1432 [PARTITION_ROOT_VERITY] = "root-verity",
1433 [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
8c1be37e
LP
1434};
1435
1436DEFINE_STRING_TABLE_LOOKUP(partition_designator, int);