Ejemplo n.º 1
0
static int status_variables(void) {
        int n_options, n_order;
        uint16_t *options = NULL, *order = NULL;
        int r, i;

        if (!is_efi_boot()) {
                fprintf(stderr, "Not booted with EFI, not showing EFI variables.\n");
                return 0;
        }

        n_options = efi_get_boot_options(&options);
        if (n_options < 0) {
                if (n_options == -ENOENT)
                        fprintf(stderr, "Failed to access EFI variables, "
                                "efivarfs needs to be available at /sys/firmware/efi/efivars/.\n");
                else
                        fprintf(stderr, "Failed to read EFI boot entries: %s\n", strerror(-n_options));
                r = n_options;
                goto finish;
        }

        printf("Boot Loader Entries in EFI Variables:\n");
        n_order = efi_get_boot_order(&order);
        if (n_order == -ENOENT) {
                n_order = 0;
        } else if (n_order < 0) {
                fprintf(stderr, "Failed to read EFI boot order.\n");
                r = n_order;
                goto finish;
        }

        /* print entries in BootOrder first */
        for (i = 0; i < n_order; i++)
                print_efi_option(order[i], true);

        /* print remaining entries */
        for (i = 0; i < n_options; i++) {
                int j;
                bool found = false;

                for (j = 0; j < n_order; j++)
                        if (options[i] == order[j]) {
                                found = true;
                                break;
                        }

                if (found)
                        continue;

                print_efi_option(options[i], false);
        }

        r = 0;
finish:
        free(options);
        free(order);

        return r;
}
Ejemplo n.º 2
0
static int install_variables(const char *esp_path,
                             uint32_t part, uint64_t pstart, uint64_t psize,
                             sd_id128_t uuid, const char *path,
                             bool first) {
        char *p = NULL;
        uint16_t *options = NULL;
        uint16_t slot;
        int r;

        if (!is_efi_boot()) {
                fprintf(stderr, "Not booted with EFI, skipping EFI variable setup.\n");
                return 0;
        }

        if (asprintf(&p, "%s%s", esp_path, path) < 0) {
                fprintf(stderr, "Out of memory.\n");
                return -ENOMEM;
        }

        if (access(p, F_OK) < 0) {
                if (errno == ENOENT)
                        r = 0;
                else
                        r = -errno;
                goto finish;
        }

        r = find_slot(uuid, path, &slot);
        if (r < 0) {
                if (r == -ENOENT)
                        fprintf(stderr, "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?\n");
                else
                        fprintf(stderr, "Failed to determine current boot order: %s\n", strerror(-r));
                goto finish;
        }

        if (first || r == false) {
                r = efi_add_boot_option(slot, "Linux Boot Manager",
                                        part, pstart, psize,
                                        uuid, path);
                if (r < 0) {
                        fprintf(stderr, "Failed to create EFI Boot variable entry: %s\n", strerror(-r));
                        goto finish;
                }
                fprintf(stderr, "Created EFI boot entry \"Linux Boot Manager\".\n");
        }

        insert_into_order(slot, first);

finish:
        free(p);
        free(options);
        return r;
}
Ejemplo n.º 3
0
static int status_variables(void) {
        int n_options, n_order;
        _cleanup_free_ uint16_t *options = NULL, *order = NULL;
        int i;

        if (!is_efi_boot()) {
                log_notice("Not booted with EFI, not showing EFI variables.");
                return 0;
        }

        n_options = efi_get_boot_options(&options);
        if (n_options == -ENOENT)
                return log_error_errno(ENOENT, "Failed to access EFI variables, efivarfs"
                                       " needs to be available at /sys/firmware/efi/efivars/.");
        else if (n_options < 0)
                return log_error_errno(n_options, "Failed to read EFI boot entries: %m");

        n_order = efi_get_boot_order(&order);
        if (n_order == -ENOENT)
                n_order = 0;
        else if (n_order < 0)
                return log_error_errno(n_order, "Failed to read EFI boot order.");

        /* print entries in BootOrder first */
        printf("Boot Loader Entries in EFI Variables:\n");
        for (i = 0; i < n_order; i++)
                print_efi_option(order[i], true);

        /* print remaining entries */
        for (i = 0; i < n_options; i++) {
                int j;

                for (j = 0; j < n_order; j++)
                        if (options[i] == order[j])
                                goto next;

                print_efi_option(options[i], false);
        next:
                continue;
        }

        return 0;
}
Ejemplo n.º 4
0
static int read_flag(const char *varname) {
        _cleanup_free_ void *v = NULL;
        uint8_t b;
        size_t s;
        int r;

        if (!is_efi_boot()) /* If this is not an EFI boot, assume the queried flags are zero */
                return 0;

        r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
        if (r < 0)
                return r;

        if (s != 1)
                return -EINVAL;

        b = *(uint8_t *)v;
        return !!b;
}
Ejemplo n.º 5
0
static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
        uint16_t slot;
        int r;

        if (!is_efi_boot())
                return 0;

        r = find_slot(uuid, path, &slot);
        if (r != 1)
                return 0;

        r = efi_remove_boot_option(slot);
        if (r < 0)
                return r;

        if (in_order)
                return remove_from_order(slot);
        else
                return 0;
}
Ejemplo n.º 6
0
static int install_variables(const char *esp_path,
                             uint32_t part, uint64_t pstart, uint64_t psize,
                             sd_id128_t uuid, const char *path,
                             bool first) {
        char *p;
        uint16_t slot;
        int r;

        if (!is_efi_boot()) {
                log_warning("Not booted with EFI, skipping EFI variable setup.");
                return 0;
        }

        p = strjoina(esp_path, path);
        if (access(p, F_OK) < 0) {
                if (errno == ENOENT)
                        return 0;
                else
                        return log_error_errno(errno, "Cannot access \"%s\": %m", p);
        }

        r = find_slot(uuid, path, &slot);
        if (r < 0)
                return log_error_errno(r,
                                       r == -ENOENT ?
                                       "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?" :
                                       "Failed to determine current boot order: %m");

        if (first || r == false) {
                r = efi_add_boot_option(slot, "Linux Boot Manager",
                                        part, pstart, psize,
                                        uuid, path);
                if (r < 0)
                        return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");

                log_info("Created EFI boot entry \"Linux Boot Manager\".");
        }

        return insert_into_order(slot, first);
}
Ejemplo n.º 7
0
int efi_reboot_to_firmware_supported(void) {
        _cleanup_free_ void *v = NULL;
        uint64_t b;
        size_t s;
        int r;

        if (!is_efi_boot())
                return -EOPNOTSUPP;

        r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
        if (r == -ENOENT) /* variable doesn't exist? it's not supported then */
                return -EOPNOTSUPP;
        if (r < 0)
                return r;
        if (s != sizeof(uint64_t))
                return -EINVAL;

        b = *(uint64_t*) v;
        if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
                return -EOPNOTSUPP; /* bit unset? it's not supported then */

        return 0;
}
Ejemplo n.º 8
0
static int bootctl_main(int argc, char*argv[]) {
        enum action {
                ACTION_STATUS,
                ACTION_INSTALL,
                ACTION_UPDATE,
                ACTION_REMOVE
        } arg_action = ACTION_STATUS;
        static const struct {
                const char* verb;
                enum action action;
        } verbs[] = {
                { "status",  ACTION_STATUS },
                { "install", ACTION_INSTALL },
                { "update",  ACTION_UPDATE },
                { "remove",  ACTION_REMOVE },
        };

        sd_id128_t uuid = {};
        uint32_t part = 0;
        uint64_t pstart = 0, psize = 0;
        int r, q;

        if (argv[optind]) {
                unsigned i;

                for (i = 0; i < ELEMENTSOF(verbs); i++) {
                        if (!streq(argv[optind], verbs[i].verb))
                                continue;
                        arg_action = verbs[i].action;
                        break;
                }
                if (i >= ELEMENTSOF(verbs)) {
                        log_error("Unknown operation \"%s\"", argv[optind]);
                        return -EINVAL;
                }
        }

        if (geteuid() != 0)
                return log_error_errno(EPERM, "Need to be root.");

        r = verify_esp(arg_path, &part, &pstart, &psize, &uuid);
        if (r == -ENODEV && !arg_path)
                log_notice("You might want to use --path= to indicate the path to your ESP, in case it is not mounted on /boot.");
        if (r < 0)
                return r;

        switch (arg_action) {
        case ACTION_STATUS: {
                _cleanup_free_ char *fw_type = NULL;
                _cleanup_free_ char *fw_info = NULL;
                _cleanup_free_ char *loader = NULL;
                _cleanup_free_ char *loader_path = NULL;
                sd_id128_t loader_part_uuid = {};

                if (is_efi_boot()) {
                        read_loader_efi_var("LoaderFirmwareType", &fw_type);
                        read_loader_efi_var("LoaderFirmwareInfo", &fw_info);
                        read_loader_efi_var("LoaderInfo", &loader);
                        read_loader_efi_var("LoaderImageIdentifier", &loader_path);
                        if (loader_path)
                                efi_tilt_backslashes(loader_path);
                        r = efi_loader_get_device_part_uuid(&loader_part_uuid);
                        if (r < 0 && r == -ENOENT)
                                log_warning_errno(r, "Failed to read EFI variable LoaderDevicePartUUID: %m");

                        printf("System:\n");
                        printf("     Firmware: %s (%s)\n", strna(fw_type), strna(fw_info));

                        r = is_efi_secure_boot();
                        if (r < 0)
                                log_warning_errno(r, "Failed to query secure boot status: %m");
                        else
                                printf("  Secure Boot: %s\n", r ? "enabled" : "disabled");

                        r = is_efi_secure_boot_setup_mode();
                        if (r < 0)
                                log_warning_errno(r, "Failed to query secure boot mode: %m");
                        else
                                printf("   Setup Mode: %s\n", r ? "setup" : "user");
                        printf("\n");

                        printf("Loader:\n");
                        printf("      Product: %s\n", strna(loader));
                        if (!sd_id128_equal(loader_part_uuid, SD_ID128_NULL))
                                printf("    Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
                                       SD_ID128_FORMAT_VAL(loader_part_uuid));
                        else
                                printf("    Partition: n/a\n");
                        printf("         File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
                        printf("\n");
                } else
                        printf("System:\n    Not booted with EFI\n");

                r = status_binaries(arg_path, uuid);
                if (r < 0)
                        return r;

                if (arg_touch_variables)
                        r = status_variables();
                break;
        }

        case ACTION_INSTALL:
        case ACTION_UPDATE:
                umask(0002);

                r = install_binaries(arg_path, arg_action == ACTION_INSTALL);
                if (r < 0)
                        return r;

                if (arg_action == ACTION_INSTALL) {
                        r = install_loader_config(arg_path);
                        if (r < 0)
                                return r;
                }

                if (arg_touch_variables)
                        r = install_variables(arg_path,
                                              part, pstart, psize, uuid,
                                              "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
                                              arg_action == ACTION_INSTALL);
                break;

        case ACTION_REMOVE:
                r = remove_binaries(arg_path);

                if (arg_touch_variables) {
                        q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
                        if (q < 0 && r == 0)
                                r = q;
                }
                break;
        }

        return r;
}
Ejemplo n.º 9
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;
        int r;

        assert(what);

        if (!is_efi_boot()) {
                log_debug("Not an EFI boot, ignoring /boot.");
                return 0;
        }

        if (in_initrd()) {
                log_debug("In initrd, ignoring /boot.");
                return 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;
        }

        r = efi_loader_get_device_part_uuid(&id);
        if (r == -ENOENT) {
                log_debug("EFI loader partition unknown.");
                return 0;
        }

        if (r < 0) {
                log_error_errno(r, "Failed to read ESP partition UUID: %m");
                return r;
        }

        errno = 0;
        b = blkid_new_probe_from_filename(what);
        if (!b) {
                if (errno == 0)
                        return log_oom();
                return log_error_errno(errno, "Failed to allocate prober: %m");
        }

        blkid_probe_enable_partitions(b, 1);
        blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);

        errno = 0;
        r = blkid_do_safeprobe(b);
        if (r == -2 || r == 1) /* no result or uncertain */
                return 0;
        else if (r != 0)
                return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);

        (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
        if (!streq(fstype, "vfat")) {
                log_debug("Partition for /boot is not a FAT filesystem, ignoring.");
                return 0;
        }

        r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL);
        if (r != 0) {
                log_debug_errno(r, "Partition for /boot does not have a UUID, ignoring. %m");
                return 0;
        }

        if (sd_id128_from_string(uuid, &type_id) < 0) {
                log_debug("Partition for /boot does not have a valid UUID, ignoring.");
                return 0;
        }

        if (!sd_id128_equal(type_id, id)) {
                log_debug("Partition for /boot does not appear to be the partition we are booted from.");
                return 0;
        }

        r = add_automount("boot",
                       what,
                       "/boot",
                       "vfat",
                       true,
                       "umask=0077",
                       "EFI System Partition Automount",
                       120 * USEC_PER_SEC);

        return r;
}
int main(int argc, char *argv[]) {
    _cleanup_free_ char *what = NULL;
    _cleanup_fclose_ FILE *f = NULL;
    int r = EXIT_SUCCESS;
    sd_id128_t id;
    char *name;

    if (argc > 1 && argc != 4) {
        log_error("This program takes three or no arguments.");
        return EXIT_FAILURE;
    }

    if (argc > 1)
        arg_dest = argv[3];

    log_set_target(LOG_TARGET_SAFE);
    log_parse_environment();
    log_open();

    umask(0022);

    if (in_initrd()) {
        log_debug("In initrd, exiting.");
        return EXIT_SUCCESS;
    }

    if (detect_container(NULL) > 0) {
        log_debug("In a container, exiting.");
        return EXIT_SUCCESS;
    }

    if (!is_efi_boot()) {
        log_debug("Not an EFI boot, exiting.");
        return EXIT_SUCCESS;
    }

    if (path_is_mount_point("/boot", true) <= 0 &&
            dir_is_empty("/boot") <= 0) {
        log_debug("/boot already populated, exiting.");
        return EXIT_SUCCESS;
    }

    r = efi_loader_get_device_part_uuid(&id);
    if (r == -ENOENT) {
        log_debug("EFI loader partition unknown, exiting.");
        return EXIT_SUCCESS;
    } else if (r < 0) {
        log_error_errno(r, "Failed to read ESP partition UUID: %m");
        return EXIT_FAILURE;
    }

    name = strjoina(arg_dest, "/boot.mount");
    f = fopen(name, "wxe");
    if (!f) {
        log_error_errno(errno, "Failed to create mount unit file %s: %m", name);
        return EXIT_FAILURE;
    }

    r = asprintf(&what,
                 "/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
                 SD_ID128_FORMAT_VAL(id));
    if (r < 0) {
        log_oom();
        return EXIT_FAILURE;
    }

    fprintf(f,
            "# Automatially generated by systemd-efi-boot-generator\n\n"
            "[Unit]\n"
            "Description=EFI System Partition\n"
            "Documentation=man:systemd-efi-boot-generator(8)\n");

    r = generator_write_fsck_deps(f, arg_dest, what, "/boot", "vfat");
    if (r < 0)
        return EXIT_FAILURE;

    fprintf(f,
            "\n"
            "[Mount]\n"
            "What=%s\n"
            "Where=/boot\n"
            "Type=vfat\n"
            "Options=umask=0077,noauto\n",
            what);

    fflush(f);
    if (ferror(f)) {
        log_error_errno(errno, "Failed to write mount unit file: %m");
        return EXIT_FAILURE;
    }

    name = strjoina(arg_dest, "/boot.automount");
    fclose(f);
    f = fopen(name, "wxe");
    if (!f) {
        log_error_errno(errno, "Failed to create automount unit file %s: %m", name);
        return EXIT_FAILURE;
    }

    fputs("# Automatially generated by systemd-efi-boot-generator\n\n"
          "[Unit]\n"
          "Description=EFI System Partition Automount\n\n"
          "[Automount]\n"
          "Where=/boot\n", f);

    fflush(f);
    if (ferror(f)) {
        log_error_errno(errno, "Failed to write automount unit file: %m");
        return EXIT_FAILURE;
    }

    name = strjoina(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/boot.automount");
    mkdir_parents(name, 0755);

    if (symlink("../boot.automount", name) < 0) {
        log_error_errno(errno, "Failed to create symlink %s: %m", name);
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}