+static int status_binaries(const char *esp_path, sd_id128_t partition) {
+ int r;
+
+ printf("Boot Loader Binaries:\n");
+
+ printf(" ESP: /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(partition));
+
+ r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
+ if (r == 0)
+ fprintf(stderr, "systemd-boot not installed in ESP.\n");
+ else if (r < 0)
+ return r;
+
+ r = enumerate_binaries(esp_path, "EFI/Boot", "boot");
+ if (r == 0)
+ fprintf(stderr, "No default/fallback boot loader installed in ESP.\n");
+ else if (r < 0)
+ return r;
+
+ printf("\n");
+ return 0;
+}
+
+static int print_efi_option(uint16_t id, bool in_order) {
+ _cleanup_free_ char *title = NULL;
+ _cleanup_free_ char *path = NULL;
+ sd_id128_t partition;
+ bool active;
+ int r = 0;
+
+ r = efi_get_boot_option(id, &title, &partition, &path, &active);
+ if (r < 0)
+ return r;
+
+ /* print only configured entries with partition information */
+ if (!path || sd_id128_equal(partition, SD_ID128_NULL))
+ return 0;
+
+ efi_tilt_backslashes(path);
+
+ printf(" Title: %s\n", strna(title));
+ printf(" ID: 0x%04X\n", id);
+ printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
+ 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(partition));
+ printf(" File: └─%s\n", path);
+ printf("\n");
+
+ return 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;
+}
+
+static int compare_product(const char *a, const char *b) {
+ size_t x, y;
+
+ assert(a);
+ assert(b);
+
+ x = strcspn(a, " ");
+ y = strcspn(b, " ");
+ if (x != y)
+ return x < y ? -1 : x > y ? 1 : 0;
+
+ return strncmp(a, b, x);
+}
+
+static int compare_version(const char *a, const char *b) {
+ assert(a);
+ assert(b);
+
+ a += strcspn(a, " ");
+ a += strspn(a, " ");
+ b += strcspn(b, " ");
+ b += strspn(b, " ");
+
+ return strverscmp(a, b);
+}
+
+static int version_check(FILE *f, const char *from, const char *to) {
+ FILE *g = NULL;
+ char *a = NULL, *b = NULL;
+ int r;
+
+ assert(f);
+ assert(from);
+ assert(to);
+
+ r = get_file_version(f, &a);
+ if (r < 0)
+ goto finish;
+ if (r == 0) {
+ r = -EINVAL;
+ fprintf(stderr, "Source file %s does not carry version information!\n", from);
+ goto finish;
+ }
+
+ g = fopen(to, "re");
+ if (!g) {
+ if (errno == ENOENT) {
+ r = 0;
+ goto finish;
+ }
+
+ r = -errno;
+ fprintf(stderr, "Failed to open %s for reading: %m\n", to);
+ goto finish;
+ }
+
+ r = get_file_version(g, &b);
+ if (r < 0)
+ goto finish;
+ if (r == 0 || compare_product(a, b) != 0) {
+ r = -EEXIST;
+ fprintf(stderr, "Skipping %s, since it's owned by another boot loader.\n", to);
+ goto finish;
+ }
+
+ if (compare_version(a, b) < 0) {
+ r = -EEXIST;
+ fprintf(stderr, "Skipping %s, since it's a newer boot loader version already.\n", to);
+ goto finish;
+ }
+
+ r = 0;