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