1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <stdlib.h>
4 #include <sys/file.h>
5 #include <unistd.h>
6 
7 #include "sd-device.h"
8 #include "sd-id128.h"
9 
10 #include "alloc-util.h"
11 #include "blkid-util.h"
12 #include "blockdev-util.h"
13 #include "btrfs-util.h"
14 #include "device-util.h"
15 #include "devnum-util.h"
16 #include "dirent-util.h"
17 #include "dissect-image.h"
18 #include "dropin.h"
19 #include "efi-loader.h"
20 #include "fd-util.h"
21 #include "fileio.h"
22 #include "fs-util.h"
23 #include "fstab-util.h"
24 #include "generator.h"
25 #include "gpt.h"
26 #include "mkdir.h"
27 #include "mountpoint-util.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "proc-cmdline.h"
31 #include "special.h"
32 #include "specifier.h"
33 #include "stat-util.h"
34 #include "string-util.h"
35 #include "strv.h"
36 #include "unit-name.h"
37 #include "util.h"
38 #include "virt.h"
39 
40 static const char *arg_dest = NULL;
41 static bool arg_enabled = true;
42 static bool arg_root_enabled = true;
43 static int arg_root_rw = -1;
44 
open_parent_block_device(dev_t devnum,int * ret_fd)45 static int open_parent_block_device(dev_t devnum, int *ret_fd) {
46         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
47         const char *name, *devtype, *node;
48         sd_device *parent;
49         dev_t pn;
50         int fd, r;
51 
52         assert(ret_fd);
53 
54         r = sd_device_new_from_devnum(&d, 'b', devnum);
55         if (r < 0)
56                 return log_debug_errno(r, "Failed to open device: %m");
57 
58         if (sd_device_get_devname(d, &name) < 0) {
59                 r = sd_device_get_syspath(d, &name);
60                 if (r < 0) {
61                         log_device_debug_errno(d, r, "Device " DEVNUM_FORMAT_STR " does not have a name, ignoring: %m",
62                                                DEVNUM_FORMAT_VAL(devnum));
63                         return 0;
64                 }
65         }
66 
67         r = sd_device_get_parent(d, &parent);
68         if (r < 0) {
69                 log_device_debug_errno(d, r, "Not a partitioned device, ignoring: %m");
70                 return 0;
71         }
72 
73         /* Does it have a devtype? */
74         r = sd_device_get_devtype(parent, &devtype);
75         if (r < 0) {
76                 log_device_debug_errno(parent, r, "Parent doesn't have a device type, ignoring: %m");
77                 return 0;
78         }
79 
80         /* Is this a disk or a partition? We only care for disks... */
81         if (!streq(devtype, "disk")) {
82                 log_device_debug(parent, "Parent isn't a raw disk, ignoring.");
83                 return 0;
84         }
85 
86         /* Does it have a device node? */
87         r = sd_device_get_devname(parent, &node);
88         if (r < 0) {
89                 log_device_debug_errno(parent, r, "Parent device does not have device node, ignoring: %m");
90                 return 0;
91         }
92 
93         log_device_debug(d, "Root device %s.", node);
94 
95         r = sd_device_get_devnum(parent, &pn);
96         if (r < 0) {
97                 log_device_debug_errno(parent, r, "Parent device is not a proper block device, ignoring: %m");
98                 return 0;
99         }
100 
101         fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
102         if (fd < 0)
103                 return log_error_errno(errno, "Failed to open %s: %m", node);
104 
105         *ret_fd = fd;
106         return 1;
107 }
108 
add_cryptsetup(const char * id,const char * what,bool rw,bool require,char ** device)109 static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
110 #if HAVE_LIBCRYPTSETUP
111         _cleanup_free_ char *e = NULL, *n = NULL, *d = NULL;
112         _cleanup_fclose_ FILE *f = NULL;
113         int r;
114 
115         assert(id);
116         assert(what);
117 
118         r = unit_name_from_path(what, ".device", &d);
119         if (r < 0)
120                 return log_error_errno(r, "Failed to generate unit name: %m");
121 
122         e = unit_name_escape(id);
123         if (!e)
124                 return log_oom();
125 
126         r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
127         if (r < 0)
128                 return log_error_errno(r, "Failed to generate unit name: %m");
129 
130         r = generator_open_unit_file(arg_dest, NULL, n, &f);
131         if (r < 0)
132                 return r;
133 
134         r = generator_write_cryptsetup_unit_section(f, NULL);
135         if (r < 0)
136                 return r;
137 
138         fprintf(f,
139                 "Before=umount.target cryptsetup.target\n"
140                 "Conflicts=umount.target\n"
141                 "BindsTo=%s\n"
142                 "After=%s\n",
143                 d, d);
144 
145         r = generator_write_cryptsetup_service_section(f, id, what, NULL, rw ? NULL : "read-only");
146         if (r < 0)
147                 return r;
148 
149         r = fflush_and_check(f);
150         if (r < 0)
151                 return log_error_errno(r, "Failed to write file %s: %m", n);
152 
153         r = generator_add_symlink(arg_dest, d, "wants", n);
154         if (r < 0)
155                 return r;
156 
157         const char *dmname;
158         dmname = strjoina("dev-mapper-", e, ".device");
159 
160         if (require) {
161                 r = generator_add_symlink(arg_dest, "cryptsetup.target", "requires", n);
162                 if (r < 0)
163                         return r;
164 
165                 r = generator_add_symlink(arg_dest, dmname, "requires", n);
166                 if (r < 0)
167                         return r;
168         }
169 
170         r = write_drop_in_format(arg_dest, dmname, 50, "job-timeout",
171                                  "# Automatically generated by systemd-gpt-auto-generator\n\n"
172                                  "[Unit]\n"
173                                  "JobTimeoutSec=0"); /* the binary handles timeouts anyway */
174         if (r < 0)
175                 log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m");
176 
177         if (device) {
178                 char *ret;
179 
180                 ret = path_join("/dev/mapper", id);
181                 if (!ret)
182                         return log_oom();
183 
184                 *device = ret;
185         }
186 
187         return 0;
188 #else
189         return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Partition is encrypted, but the project was compiled without libcryptsetup support");
190 #endif
191 }
192 
add_mount(const char * id,const char * what,const char * where,const char * fstype,bool rw,bool growfs,const char * options,const char * description,const char * post)193 static int add_mount(
194                 const char *id,
195                 const char *what,
196                 const char *where,
197                 const char *fstype,
198                 bool rw,
199                 bool growfs,
200                 const char *options,
201                 const char *description,
202                 const char *post) {
203 
204         _cleanup_free_ char *unit = NULL, *crypto_what = NULL, *p = NULL;
205         _cleanup_fclose_ FILE *f = NULL;
206         int r;
207 
208         /* Note that we don't apply specifier escaping on the input strings here, since we know they are not configured
209          * externally, but all originate from our own sources here, and hence we know they contain no % characters that
210          * could potentially be understood as specifiers. */
211 
212         assert(id);
213         assert(what);
214         assert(where);
215         assert(description);
216 
217         log_debug("Adding %s: %s fstype=%s", where, what, fstype ?: "(any)");
218 
219         if (streq_ptr(fstype, "crypto_LUKS")) {
220                 r = add_cryptsetup(id, what, rw, true, &crypto_what);
221                 if (r < 0)
222                         return r;
223 
224                 what = crypto_what;
225                 fstype = NULL;
226         }
227 
228         r = unit_name_from_path(where, ".mount", &unit);
229         if (r < 0)
230                 return log_error_errno(r, "Failed to generate unit name: %m");
231 
232         p = path_join(empty_to_root(arg_dest), unit);
233         if (!p)
234                 return log_oom();
235 
236         f = fopen(p, "wxe");
237         if (!f)
238                 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
239 
240         fprintf(f,
241                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
242                 "[Unit]\n"
243                 "Description=%s\n"
244                 "Documentation=man:systemd-gpt-auto-generator(8)\n",
245                 description);
246 
247         if (post)
248                 fprintf(f, "Before=%s\n", post);
249 
250         r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
251         if (r < 0)
252                 return r;
253 
254         r = generator_write_blockdev_dependency(f, what);
255         if (r < 0)
256                 return r;
257 
258         fprintf(f,
259                 "\n"
260                 "[Mount]\n"
261                 "What=%s\n"
262                 "Where=%s\n",
263                 what, where);
264 
265         if (fstype)
266                 fprintf(f, "Type=%s\n", fstype);
267 
268         if (options)
269                 fprintf(f, "Options=%s,%s\n", options, rw ? "rw" : "ro");
270         else
271                 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
272 
273         r = fflush_and_check(f);
274         if (r < 0)
275                 return log_error_errno(r, "Failed to write unit file %s: %m", p);
276 
277         if (growfs) {
278                 r = generator_hook_up_growfs(arg_dest, where, post);
279                 if (r < 0)
280                         return r;
281         }
282 
283         if (post) {
284                 r = generator_add_symlink(arg_dest, post, "requires", unit);
285                 if (r < 0)
286                         return r;
287         }
288 
289         return 0;
290 }
291 
path_is_busy(const char * where)292 static int path_is_busy(const char *where) {
293         int r;
294 
295         /* already a mountpoint; generators run during reload */
296         r = path_is_mount_point(where, NULL, AT_SYMLINK_FOLLOW);
297         if (r > 0)
298                 return false;
299 
300         /* the directory might not exist on a stateless system */
301         if (r == -ENOENT)
302                 return false;
303 
304         if (r < 0)
305                 return log_warning_errno(r, "Cannot check if \"%s\" is a mount point: %m", where);
306 
307         /* not a mountpoint but it contains files */
308         r = dir_is_empty(where, /* ignore_hidden_or_backup= */ false);
309         if (r < 0)
310                 return log_warning_errno(r, "Cannot check if \"%s\" is empty: %m", where);
311         if (r > 0)
312                 return false;
313 
314         log_debug("\"%s\" already populated, ignoring.", where);
315         return true;
316 }
317 
add_partition_mount(DissectedPartition * p,const char * id,const char * where,const char * description)318 static int add_partition_mount(
319                 DissectedPartition *p,
320                 const char *id,
321                 const char *where,
322                 const char *description) {
323 
324         int r;
325         assert(p);
326 
327         r = path_is_busy(where);
328         if (r != 0)
329                 return r < 0 ? r : 0;
330 
331         return add_mount(
332                         id,
333                         p->node,
334                         where,
335                         p->fstype,
336                         p->rw,
337                         p->growfs,
338                         NULL,
339                         description,
340                         SPECIAL_LOCAL_FS_TARGET);
341 }
342 
add_swap(DissectedPartition * p)343 static int add_swap(DissectedPartition *p) {
344         const char *what;
345         _cleanup_free_ char *name = NULL, *unit = NULL, *crypto_what = NULL;
346         _cleanup_fclose_ FILE *f = NULL;
347         int r;
348 
349         assert(p);
350         assert(p->node);
351 
352         /* Disable the swap auto logic if at least one swap is defined in /etc/fstab, see #6192. */
353         r = fstab_has_fstype("swap");
354         if (r < 0)
355                 return log_error_errno(r, "Failed to parse fstab: %m");
356         if (r > 0) {
357                 log_debug("swap specified in fstab, ignoring.");
358                 return 0;
359         }
360 
361         if (streq_ptr(p->fstype, "crypto_LUKS")) {
362                 r = add_cryptsetup("swap", p->node, true, true, &crypto_what);
363                 if (r < 0)
364                         return r;
365                 what = crypto_what;
366         } else
367                 what = p->node;
368 
369         log_debug("Adding swap: %s", what);
370 
371         r = unit_name_from_path(what, ".swap", &name);
372         if (r < 0)
373                 return log_error_errno(r, "Failed to generate unit name: %m");
374 
375         unit = path_join(empty_to_root(arg_dest), name);
376         if (!unit)
377                 return log_oom();
378 
379         f = fopen(unit, "wxe");
380         if (!f)
381                 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
382 
383         fprintf(f,
384                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
385                 "[Unit]\n"
386                 "Description=Swap Partition\n"
387                 "Documentation=man:systemd-gpt-auto-generator(8)\n");
388 
389         r = generator_write_blockdev_dependency(f, what);
390         if (r < 0)
391                 return r;
392 
393         fprintf(f,
394                 "\n"
395                 "[Swap]\n"
396                 "What=%s\n",
397                 what);
398 
399         r = fflush_and_check(f);
400         if (r < 0)
401                 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
402 
403         return generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, "wants", name);
404 }
405 
add_automount(const char * id,const char * what,const char * where,const char * fstype,bool rw,bool growfs,const char * options,const char * description,usec_t timeout)406 static int add_automount(
407                 const char *id,
408                 const char *what,
409                 const char *where,
410                 const char *fstype,
411                 bool rw,
412                 bool growfs,
413                 const char *options,
414                 const char *description,
415                 usec_t timeout) {
416 
417         _cleanup_free_ char *unit = NULL;
418         _cleanup_fclose_ FILE *f = NULL;
419         const char *opt = "noauto", *p;
420         int r;
421 
422         assert(id);
423         assert(where);
424         assert(description);
425 
426         if (options)
427                 opt = strjoina(options, ",", opt);
428 
429         r = add_mount(id,
430                       what,
431                       where,
432                       fstype,
433                       rw,
434                       growfs,
435                       opt,
436                       description,
437                       NULL);
438         if (r < 0)
439                 return r;
440 
441         r = unit_name_from_path(where, ".automount", &unit);
442         if (r < 0)
443                 return log_error_errno(r, "Failed to generate unit name: %m");
444 
445         p = prefix_roota(arg_dest, unit);
446         f = fopen(p, "wxe");
447         if (!f)
448                 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
449 
450         fprintf(f,
451                 "# Automatically generated by systemd-gpt-auto-generator\n\n"
452                 "[Unit]\n"
453                 "Description=%s\n"
454                 "Documentation=man:systemd-gpt-auto-generator(8)\n"
455                 "[Automount]\n"
456                 "Where=%s\n"
457                 "TimeoutIdleSec="USEC_FMT"\n",
458                 description,
459                 where,
460                 timeout / USEC_PER_SEC);
461 
462         r = fflush_and_check(f);
463         if (r < 0)
464                 return log_error_errno(r, "Failed to write unit file %s: %m", p);
465 
466         return generator_add_symlink(arg_dest, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
467 }
468 
esp_or_xbootldr_options(const DissectedPartition * p)469 static const char *esp_or_xbootldr_options(const DissectedPartition *p) {
470         assert(p);
471 
472         /* if we probed vfat or have no idea about the file system then assume these file systems are vfat
473          * and thus understand "umask=0077". If we detected something else then don't specify any options and
474          * use kernel defaults. */
475 
476         if (!p->fstype || streq(p->fstype, "vfat"))
477                 return "umask=0077";
478 
479         return NULL;
480 }
481 
add_xbootldr(DissectedPartition * p)482 static int add_xbootldr(DissectedPartition *p) {
483         int r;
484 
485         assert(p);
486 
487         if (in_initrd()) {
488                 log_debug("In initrd, ignoring the XBOOTLDR partition.");
489                 return 0;
490         }
491 
492         r = fstab_is_mount_point("/boot");
493         if (r < 0)
494                 return log_error_errno(r, "Failed to parse fstab: %m");
495         if (r > 0) {
496                 log_debug("/boot specified in fstab, ignoring XBOOTLDR partition.");
497                 return 0;
498         }
499 
500         r = path_is_busy("/boot");
501         if (r < 0)
502                 return r;
503         if (r > 0)
504                 return 0;
505 
506         return add_automount("boot",
507                              p->node,
508                              "/boot",
509                              p->fstype,
510                              /* rw= */ true,
511                              /* growfs= */ false,
512                              esp_or_xbootldr_options(p),
513                              "Boot Loader Partition",
514                              120 * USEC_PER_SEC);
515 }
516 
517 #if ENABLE_EFI
add_esp(DissectedPartition * p,bool has_xbootldr)518 static int add_esp(DissectedPartition *p, bool has_xbootldr) {
519         const char *esp_path = NULL, *id = NULL;
520         int r;
521 
522         assert(p);
523 
524         if (in_initrd()) {
525                 log_debug("In initrd, ignoring the ESP.");
526                 return 0;
527         }
528 
529         /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice, but
530          * only if there's no explicit XBOOTLDR partition around. */
531         if (access("/efi", F_OK) < 0) {
532                 if (errno != ENOENT)
533                         return log_error_errno(errno, "Failed to determine whether /efi exists: %m");
534 
535                 /* Use /boot as fallback, but only if there's no XBOOTLDR partition */
536                 if (!has_xbootldr) {
537                         esp_path = "/boot";
538                         id = "boot";
539                 }
540         }
541         if (!esp_path)
542                 esp_path = "/efi";
543         if (!id)
544                 id = "efi";
545 
546         /* We create an .automount which is not overridden by the .mount from the fstab generator. */
547         r = fstab_is_mount_point(esp_path);
548         if (r < 0)
549                 return log_error_errno(r, "Failed to parse fstab: %m");
550         if (r > 0) {
551                 log_debug("%s specified in fstab, ignoring.", esp_path);
552                 return 0;
553         }
554 
555         r = path_is_busy(esp_path);
556         if (r < 0)
557                 return r;
558         if (r > 0)
559                 return 0;
560 
561         if (is_efi_boot()) {
562                 sd_id128_t loader_uuid;
563 
564                 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
565 
566                 r = efi_loader_get_device_part_uuid(&loader_uuid);
567                 if (r == -ENOENT) {
568                         log_debug("EFI loader partition unknown.");
569                         return 0;
570                 }
571                 if (r < 0)
572                         return log_error_errno(r, "Failed to read ESP partition UUID: %m");
573 
574                 if (!sd_id128_equal(p->uuid, loader_uuid)) {
575                         log_debug("Partition for %s does not appear to be the partition we are booted from.", p->node);
576                         return 0;
577                 }
578         } else
579                 log_debug("Not an EFI boot, skipping ESP check.");
580 
581         return add_automount(id,
582                              p->node,
583                              esp_path,
584                              p->fstype,
585                              /* rw= */ true,
586                              /* growfs= */ false,
587                              esp_or_xbootldr_options(p),
588                              "EFI System Partition Automount",
589                              120 * USEC_PER_SEC);
590 }
591 #else
add_esp(DissectedPartition * p,bool has_xbootldr)592 static int add_esp(DissectedPartition *p, bool has_xbootldr) {
593         return 0;
594 }
595 #endif
596 
add_root_rw(DissectedPartition * p)597 static int add_root_rw(DissectedPartition *p) {
598         const char *path;
599         int r;
600 
601         assert(p);
602 
603         if (in_initrd()) {
604                 log_debug("In initrd, not generating drop-in for systemd-remount-fs.service.");
605                 return 0;
606         }
607 
608         if (arg_root_rw >= 0) {
609                 log_debug("Parameter ro/rw specified on kernel command line, not generating drop-in for systemd-remount-fs.service.");
610                 return 0;
611         }
612 
613         if (!p->rw) {
614                 log_debug("Root partition marked read-only in GPT partition table, not generating drop-in for systemd-remount-fs.service.");
615                 return 0;
616         }
617 
618         (void) generator_enable_remount_fs_service(arg_dest);
619 
620         path = strjoina(arg_dest, "/systemd-remount-fs.service.d/50-remount-rw.conf");
621 
622         r = write_string_file(path,
623                               "# Automatically generated by systemd-gpt-generator\n\n"
624                               "[Service]\n"
625                               "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
626                               WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW|WRITE_STRING_FILE_MKDIR_0755);
627         if (r < 0)
628                 return log_error_errno(r, "Failed to write drop-in file %s: %m", path);
629 
630         return 0;
631 }
632 
633 #if ENABLE_EFI
add_root_cryptsetup(void)634 static int add_root_cryptsetup(void) {
635 
636         /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
637          * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
638 
639         return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL);
640 }
641 #endif
642 
add_root_mount(void)643 static int add_root_mount(void) {
644 #if ENABLE_EFI
645         int r;
646 
647         if (!is_efi_boot()) {
648                 log_debug("Not an EFI boot, not creating root mount.");
649                 return 0;
650         }
651 
652         r = efi_loader_get_device_part_uuid(NULL);
653         if (r == -ENOENT) {
654                 log_notice("EFI loader partition unknown, exiting.\n"
655                            "(The boot loader did not set EFI variable LoaderDevicePartUUID.)");
656                 return 0;
657         } else if (r < 0)
658                 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
659 
660         /* OK, we have an ESP partition, this is fantastic, so let's
661          * wait for a root device to show up. A udev rule will create
662          * the link for us under the right name. */
663 
664         if (in_initrd()) {
665                 r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
666                 if (r < 0)
667                         return 0;
668 
669                 r = add_root_cryptsetup();
670                 if (r < 0)
671                         return r;
672         }
673 
674         /* Note that we do not need to enable systemd-remount-fs.service here. If
675          * /etc/fstab exists, systemd-fstab-generator will pull it in for us. */
676 
677         return add_mount(
678                         "root",
679                         "/dev/gpt-auto-root",
680                         in_initrd() ? "/sysroot" : "/",
681                         NULL,
682                         /* rw= */ arg_root_rw > 0,
683                         /* growfs= */ false,
684                         NULL,
685                         "Root Partition",
686                         in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
687 #else
688         return 0;
689 #endif
690 }
691 
enumerate_partitions(dev_t devnum)692 static int enumerate_partitions(dev_t devnum) {
693         _cleanup_close_ int fd = -1;
694         _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
695         int r, k;
696 
697         r = open_parent_block_device(devnum, &fd);
698         if (r <= 0)
699                 return r;
700 
701         /* Let's take a LOCK_SH lock on the block device, in case udevd is already running. If we don't take
702          * the lock, udevd might end up issuing BLKRRPART in the middle, and we don't want that, since that
703          * might remove all partitions while we are operating on them. */
704         if (flock(fd, LOCK_SH) < 0)
705                 return log_error_errno(errno, "Failed to lock root block device: %m");
706 
707         r = dissect_image(
708                         fd,
709                         NULL, NULL,
710                         /* diskseq= */ 0,
711                         UINT64_MAX,
712                         USEC_INFINITY,
713                         DISSECT_IMAGE_GPT_ONLY|
714                         DISSECT_IMAGE_USR_NO_ROOT,
715                         &m);
716         if (r == -ENOPKG) {
717                 log_debug_errno(r, "No suitable partition table found, ignoring.");
718                 return 0;
719         }
720         if (r < 0)
721                 return log_error_errno(r, "Failed to dissect: %m");
722 
723         if (m->partitions[PARTITION_SWAP].found) {
724                 k = add_swap(m->partitions + PARTITION_SWAP);
725                 if (k < 0)
726                         r = k;
727         }
728 
729         if (m->partitions[PARTITION_XBOOTLDR].found) {
730                 k = add_xbootldr(m->partitions + PARTITION_XBOOTLDR);
731                 if (k < 0)
732                         r = k;
733         }
734 
735         if (m->partitions[PARTITION_ESP].found) {
736                 k = add_esp(m->partitions + PARTITION_ESP, m->partitions[PARTITION_XBOOTLDR].found);
737                 if (k < 0)
738                         r = k;
739         }
740 
741         if (m->partitions[PARTITION_HOME].found) {
742                 k = add_partition_mount(m->partitions + PARTITION_HOME, "home", "/home", "Home Partition");
743                 if (k < 0)
744                         r = k;
745         }
746 
747         if (m->partitions[PARTITION_SRV].found) {
748                 k = add_partition_mount(m->partitions + PARTITION_SRV, "srv", "/srv", "Server Data Partition");
749                 if (k < 0)
750                         r = k;
751         }
752 
753         if (m->partitions[PARTITION_VAR].found) {
754                 k = add_partition_mount(m->partitions + PARTITION_VAR, "var", "/var", "Variable Data Partition");
755                 if (k < 0)
756                         r = k;
757         }
758 
759         if (m->partitions[PARTITION_TMP].found) {
760                 k = add_partition_mount(m->partitions + PARTITION_TMP, "var-tmp", "/var/tmp", "Temporary Data Partition");
761                 if (k < 0)
762                         r = k;
763         }
764 
765         if (m->partitions[PARTITION_ROOT].found) {
766                 k = add_root_rw(m->partitions + PARTITION_ROOT);
767                 if (k < 0)
768                         r = k;
769         }
770 
771         return r;
772 }
773 
add_mounts(void)774 static int add_mounts(void) {
775         _cleanup_free_ char *p = NULL;
776         int r;
777         dev_t devno;
778 
779         /* If the root mount has been replaced by some form of volatile file system (overlayfs), the
780          * original root block device node is symlinked in /run/systemd/volatile-root. Let's read that
781          * here. */
782         r = readlink_malloc("/run/systemd/volatile-root", &p);
783         if (r == -ENOENT) { /* volatile-root not found */
784                 r = get_block_device_harder("/", &devno);
785                 if (r == -EUCLEAN)
786                         return btrfs_log_dev_root(LOG_ERR, r, "root file system");
787                 if (r < 0)
788                         return log_error_errno(r, "Failed to determine block device of root file system: %m");
789                 if (r == 0) { /* Not backed by a single block device. (Could be NFS or so, or could be multi-device RAID or so) */
790                         r = get_block_device_harder("/usr", &devno);
791                         if (r == -EUCLEAN)
792                                 return btrfs_log_dev_root(LOG_ERR, r, "/usr");
793                         if (r < 0)
794                                 return log_error_errno(r, "Failed to determine block device of /usr/ file system: %m");
795                         if (r == 0) { /* /usr/ not backed by single block device, either. */
796                                 log_debug("Neither root nor /usr/ file system are on a (single) block device.");
797                                 return 0;
798                         }
799                 }
800         } else if (r < 0)
801                 return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m");
802         else {
803                 mode_t m;
804                 r = device_path_parse_major_minor(p, &m, &devno);
805                 if (r < 0)
806                         return log_error_errno(r, "Failed to parse major/minor device node: %m");
807                 if (!S_ISBLK(m))
808                         return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Volatile root device is of wrong type.");
809         }
810 
811         return enumerate_partitions(devno);
812 }
813 
parse_proc_cmdline_item(const char * key,const char * value,void * data)814 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
815         int r;
816 
817         assert(key);
818 
819         if (proc_cmdline_key_streq(key, "systemd.gpt_auto") ||
820             proc_cmdline_key_streq(key, "rd.systemd.gpt_auto")) {
821 
822                 r = value ? parse_boolean(value) : 1;
823                 if (r < 0)
824                         log_warning_errno(r, "Failed to parse gpt-auto switch \"%s\", ignoring: %m", value);
825                 else
826                         arg_enabled = r;
827 
828         } else if (proc_cmdline_key_streq(key, "root")) {
829 
830                 if (proc_cmdline_value_missing(key, value))
831                         return 0;
832 
833                 /* Disable root disk logic if there's a root= value
834                  * specified (unless it happens to be "gpt-auto") */
835 
836                 if (!streq(value, "gpt-auto")) {
837                         arg_root_enabled = false;
838                         log_debug("Disabling root partition auto-detection, root= is defined.");
839                 }
840 
841         } else if (proc_cmdline_key_streq(key, "roothash")) {
842 
843                 if (proc_cmdline_value_missing(key, value))
844                         return 0;
845 
846                 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
847 
848                 arg_root_enabled = false;
849 
850         } else if (proc_cmdline_key_streq(key, "rw") && !value)
851                 arg_root_rw = true;
852         else if (proc_cmdline_key_streq(key, "ro") && !value)
853                 arg_root_rw = false;
854 
855         return 0;
856 }
857 
run(const char * dest,const char * dest_early,const char * dest_late)858 static int run(const char *dest, const char *dest_early, const char *dest_late) {
859         int r, k;
860 
861         assert_se(arg_dest = dest_late);
862 
863         if (detect_container() > 0) {
864                 log_debug("In a container, exiting.");
865                 return 0;
866         }
867 
868         r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
869         if (r < 0)
870                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
871 
872         if (!arg_enabled) {
873                 log_debug("Disabled, exiting.");
874                 return 0;
875         }
876 
877         if (arg_root_enabled)
878                 r = add_root_mount();
879 
880         if (!in_initrd()) {
881                 k = add_mounts();
882                 if (r >= 0)
883                         r = k;
884         }
885 
886         return r;
887 }
888 
889 DEFINE_MAIN_GENERATOR_FUNCTION(run);
890