]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/gpt-auto-generator/gpt-auto-generator.c
util-lib: introduce dirent-util.[ch] for directory entry calls
[thirdparty/systemd.git] / src / gpt-auto-generator / gpt-auto-generator.c
index 40caec5ab5dd71236403b2d1bdc3596d13d7221a..f315d5ff6ec8ffe56d921817e7ea2e1affe9bede 100644 (file)
 #include <sys/statfs.h>
 #include <blkid/blkid.h>
 
-#include "sd-id128.h"
 #include "libudev.h"
-#include "path-util.h"
-#include "util.h"
-#include "mkdir.h"
+#include "sd-id128.h"
+
+#include "blkid-util.h"
+#include "btrfs-util.h"
+#include "dirent-util.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fstab-util.h"
+#include "generator.h"
+#include "gpt.h"
 #include "missing.h"
-#include "udev-util.h"
+#include "mkdir.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
 #include "special.h"
+#include "string-util.h"
+#include "udev-util.h"
 #include "unit-name.h"
+#include "util.h"
 #include "virt.h"
-#include "generator.h"
-#include "gpt.h"
-#include "fileio.h"
-#include "efivars.h"
-#include "blkid-util.h"
-#include "btrfs-util.h"
 
 static const char *arg_dest = "/tmp";
 static bool arg_enabled = true;
@@ -240,82 +247,6 @@ static int add_mount(
         return 0;
 }
 
-static int add_automount(
-                const char *id,
-                const char *what,
-                const char *where,
-                const char *fstype,
-                bool rw,
-                const char *options,
-                const char *description,
-                usec_t timeout) {
-
-        _cleanup_free_ char *unit = NULL, *lnk = NULL;
-        _cleanup_free_ char *opt, *p = NULL;
-        _cleanup_fclose_ FILE *f = NULL;
-        int r;
-
-        assert(id);
-        assert(where);
-        assert(description);
-
-        if (options)
-                opt = strjoin(options, ",noauto", NULL);
-        else
-                opt = strdup("noauto");
-        if (!opt)
-                return log_oom();
-
-        r = add_mount(id,
-                      what,
-                      where,
-                      fstype,
-                      rw,
-                      opt,
-                      description,
-                      NULL);
-        if (r < 0)
-                return r;
-
-        r = unit_name_from_path(where, ".automount", &unit);
-        if (r < 0)
-                return log_error_errno(r, "Failed to generate unit name: %m");
-
-        p = strjoin(arg_dest, "/", unit, NULL);
-        if (!p)
-                return log_oom();
-
-        f = fopen(p, "wxe");
-        if (!f)
-                return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
-
-        fprintf(f,
-                "# Automatically generated by systemd-gpt-auto-generator\n\n"
-                "[Unit]\n"
-                "Description=%s\n"
-                "Documentation=man:systemd-gpt-auto-generator(8)\n"
-                "[Automount]\n"
-                "Where=%s\n"
-                "TimeoutIdleSec=%lld\n",
-                description,
-                where,
-                (unsigned long long)timeout / USEC_PER_SEC);
-
-        r = fflush_and_check(f);
-        if (r < 0)
-                return log_error_errno(r, "Failed to write unit file %s: %m", p);
-
-        lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL);
-        if (!lnk)
-                return log_oom();
-        mkdir_parents_label(lnk, 0755);
-
-        if (symlink(p, lnk) < 0)
-                return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
-
-        return 0;
-}
-
 static bool path_is_busy(const char *where) {
         int r;
 
@@ -441,8 +372,84 @@ static int add_swap(const char *path) {
         return 0;
 }
 
-static int add_boot(const char *what) {
 #ifdef ENABLE_EFI
+static int add_automount(
+                const char *id,
+                const char *what,
+                const char *where,
+                const char *fstype,
+                bool rw,
+                const char *options,
+                const char *description,
+                usec_t timeout) {
+
+        _cleanup_free_ char *unit = NULL, *lnk = NULL;
+        _cleanup_free_ char *opt, *p = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        assert(id);
+        assert(where);
+        assert(description);
+
+        if (options)
+                opt = strjoin(options, ",noauto", NULL);
+        else
+                opt = strdup("noauto");
+        if (!opt)
+                return log_oom();
+
+        r = add_mount(id,
+                      what,
+                      where,
+                      fstype,
+                      rw,
+                      opt,
+                      description,
+                      NULL);
+        if (r < 0)
+                return r;
+
+        r = unit_name_from_path(where, ".automount", &unit);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit name: %m");
+
+        p = strjoin(arg_dest, "/", unit, NULL);
+        if (!p)
+                return log_oom();
+
+        f = fopen(p, "wxe");
+        if (!f)
+                return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
+
+        fprintf(f,
+                "# Automatically generated by systemd-gpt-auto-generator\n\n"
+                "[Unit]\n"
+                "Description=%s\n"
+                "Documentation=man:systemd-gpt-auto-generator(8)\n"
+                "[Automount]\n"
+                "Where=%s\n"
+                "TimeoutIdleSec=%lld\n",
+                description,
+                where,
+                (unsigned long long)timeout / USEC_PER_SEC);
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write unit file %s: %m", p);
+
+        lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL);
+        if (!lnk)
+                return log_oom();
+        mkdir_parents_label(lnk, 0755);
+
+        if (symlink(p, lnk) < 0)
+                return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+
+        return 0;
+}
+
+static int add_boot(const char *what) {
         _cleanup_blkid_free_probe_ blkid_probe b = NULL;
         const char *fstype = NULL, *uuid = NULL;
         sd_id128_t id, type_id;
@@ -460,11 +467,17 @@ static int add_boot(const char *what) {
                 return 0;
         }
 
-        if (detect_container(NULL) > 0) {
+        if (detect_container() > 0) {
                 log_debug("In a container, ignoring /boot.");
                 return 0;
         }
 
+        /* We create an .automount which is not overridden by the .mount from the fstab generator. */
+        if (fstab_is_mount_point("/boot")) {
+                log_debug("/boot specified in fstab, ignoring.");
+                return 0;
+        }
+
         if (path_is_busy("/boot")) {
                 log_debug("/boot already populated, ignoring.");
                 return 0;
@@ -526,16 +539,18 @@ static int add_boot(const char *what) {
                        what,
                        "/boot",
                        "vfat",
-                       "EFI System Partition Automount",
-                       false,
+                       true,
                        "umask=0077",
+                       "EFI System Partition Automount",
                        120 * USEC_PER_SEC);
 
         return r;
+}
 #else
+static int add_boot(const char *what) {
         return 0;
-#endif
 }
+#endif
 
 static int enumerate_partitions(dev_t devnum) {
 
@@ -616,9 +631,12 @@ static int enumerate_partitions(dev_t devnum) {
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (r == -2 || r == 1) /* no result or uncertain */
+        if (r == 1)
+                return 0; /* no results */
+        else if (r == -2) {
+                log_warning("%s: probe gave ambiguous results, ignoring", node);
                 return 0;
-        else if (r != 0)
+        else if (r != 0)
                 return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
 
         errno = 0;
@@ -661,6 +679,7 @@ static int enumerate_partitions(dev_t devnum) {
         first = udev_enumerate_get_list_entry(e);
         udev_list_entry_foreach(item, first) {
                 _cleanup_udev_device_unref_ struct udev_device *q;
+                unsigned long long flags;
                 const char *stype, *subnode;
                 sd_id128_t type_id;
                 blkid_partition pp;
@@ -700,10 +719,10 @@ static int enumerate_partitions(dev_t devnum) {
                 if (sd_id128_from_string(stype, &type_id) < 0)
                         continue;
 
+                flags = blkid_partition_get_flags(pp);
+
                 if (sd_id128_equal(type_id, GPT_SWAP)) {
-                        unsigned long long flags;
 
-                        flags = blkid_partition_get_flags(pp);
                         if (flags & GPT_FLAG_NO_AUTO)
                                 continue;
 
@@ -722,6 +741,10 @@ static int enumerate_partitions(dev_t devnum) {
                         if (boot && nr >= boot_nr)
                                 continue;
 
+                        /* Note that we do not honour the "no-auto"
+                         * flag for the ESP, as it is often unset, to
+                         * hide it from Windows. */
+
                         boot_nr = nr;
 
                         r = free_and_strdup(&boot, subnode);
@@ -729,9 +752,7 @@ static int enumerate_partitions(dev_t devnum) {
                                 return log_oom();
 
                 } else if (sd_id128_equal(type_id, GPT_HOME)) {
-                        unsigned long long flags;
 
-                        flags = blkid_partition_get_flags(pp);
                         if (flags & GPT_FLAG_NO_AUTO)
                                 continue;
 
@@ -747,9 +768,7 @@ static int enumerate_partitions(dev_t devnum) {
                                 return log_oom();
 
                 } else if (sd_id128_equal(type_id, GPT_SRV)) {
-                        unsigned long long flags;
 
-                        flags = blkid_partition_get_flags(pp);
                         if (flags & GPT_FLAG_NO_AUTO)
                                 continue;
 
@@ -794,6 +813,10 @@ static int get_block_device(const char *path, dev_t *dev) {
         assert(path);
         assert(dev);
 
+        /* Get's the block device directly backing a file system. If
+         * the block device is encrypted, returns the device mapper
+         * block device. */
+
         if (lstat(path, &st))
                 return -errno;
 
@@ -811,6 +834,76 @@ static int get_block_device(const char *path, dev_t *dev) {
         return 0;
 }
 
+static int get_block_device_harder(const char *path, dev_t *dev) {
+        _cleanup_closedir_ DIR *d = NULL;
+        _cleanup_free_ char *p = NULL, *t = NULL;
+        struct dirent *de, *found = NULL;
+        const char *q;
+        unsigned maj, min;
+        dev_t dt;
+        int r;
+
+        assert(path);
+        assert(dev);
+
+        /* Gets the backing block device for a file system, and
+         * handles LUKS encrypted file systems, looking for its
+         * immediate parent, if there is one. */
+
+        r = get_block_device(path, &dt);
+        if (r <= 0)
+                return r;
+
+        if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
+                return -ENOMEM;
+
+        d = opendir(p);
+        if (!d) {
+                if (errno == ENOENT)
+                        goto fallback;
+
+                return -errno;
+        }
+
+        FOREACH_DIRENT_ALL(de, d, return -errno) {
+
+                if (STR_IN_SET(de->d_name, ".", ".."))
+                        continue;
+
+                if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
+                        continue;
+
+                if (found) /* Don't try to support multiple backing block devices */
+                        goto fallback;
+
+                found = de;
+        }
+
+        if (!found)
+                goto fallback;
+
+        q = strjoina(p, "/", found->d_name, "/dev");
+
+        r = read_one_line_file(q, &t);
+        if (r == -ENOENT)
+                goto fallback;
+        if (r < 0)
+                return r;
+
+        if (sscanf(t, "%u:%u", &maj, &min) != 2)
+                return -EINVAL;
+
+        if (maj == 0)
+                goto fallback;
+
+        *dev = makedev(maj, min);
+        return 1;
+
+fallback:
+        *dev = dt;
+        return 1;
+}
+
 static int parse_proc_cmdline_item(const char *key, const char *value) {
         int r;
 
@@ -878,11 +971,11 @@ static int add_mounts(void) {
         dev_t devno;
         int r;
 
-        r = get_block_device("/", &devno);
+        r = get_block_device_harder("/", &devno);
         if (r < 0)
                 return log_error_errno(r, "Failed to determine block device of root file system: %m");
         else if (r == 0) {
-                r = get_block_device("/usr", &devno);
+                r = get_block_device_harder("/usr", &devno);
                 if (r < 0)
                         return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
                 else if (r == 0) {
@@ -911,7 +1004,7 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        if (detect_container(NULL) > 0) {
+        if (detect_container() > 0) {
                 log_debug("In a container, exiting.");
                 return EXIT_SUCCESS;
         }