static int show_status(char **args, unsigned n) { char buf[64]; struct boot_info *info; int err; err = boot_info_new(&info); if (err < 0) return -ENOMEM; err = boot_info_query(info); printf(" Machine ID: %s\n", sd_id128_to_string(info->machine_id, buf)); printf(" Boot ID: %s\n", sd_id128_to_string(info->boot_id, buf)); if (info->fw_type) printf(" Firmware: %s (%s)\n", info->fw_type, strna(info->fw_info)); if (info->fw_entry_active >= 0) { printf("Firmware entry: %s\n", strna(info->fw_entries[info->fw_entry_active].title)); if (info->fw_entries[info->fw_entry_active].path) printf(" %s\n", info->fw_entries[info->fw_entry_active].path); if (!sd_id128_equal(info->fw_entries[info->fw_entry_active].part_uuid, SD_ID128_NULL)) printf(" /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(info->fw_entries[info->fw_entry_active].part_uuid)); } if (info->loader) { printf(" Loader: %s\n", info->loader); printf(" %s\n", strna(info->loader_image_path)); if (!sd_id128_equal(info->loader_part_uuid, SD_ID128_NULL)) printf(" /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(info->loader_part_uuid)); if (info->loader_entry_active >= 0) { printf(" Loader entry: %s\n", strna(info->loader_entries[info->loader_entry_active].title)); printf(" %s\n", info->loader_entries[info->loader_entry_active].path); } printf("Loader options: %s\n", strna(info->loader_options_added)); } else printf("No suitable data is provided by the boot manager. See:\n" " http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface\n" " http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec\n" "for details.\n"); printf("\n"); boot_info_free(info); return err; }
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%s\n", special_glyph(TREE_RIGHT), path); printf("\n"); return 0; }
static int process_machine_id(void) { const char *etc_machine_id; char id[SD_ID128_STRING_MAX]; int r; etc_machine_id = prefix_roota("/etc/machine-id"); if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) return 0; if (!arg_root) return 0; if (sd_id128_equal(arg_machine_id, SD_ID128_NULL)) return 0; mkdir_parents(etc_machine_id, 0755); r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id)); if (r < 0) { log_error("Failed to write machine id: %s", strerror(-r)); return r; } log_info("%s written.", etc_machine_id); return 0; }
static int vacuum_compare(const void *_a, const void *_b) { const struct vacuum_info *a, *b; a = _a; b = _b; if (a->have_seqnum && b->have_seqnum && sd_id128_equal(a->seqnum_id, b->seqnum_id)) { if (a->seqnum < b->seqnum) return -1; else if (a->seqnum > b->seqnum) return 1; else return 0; } if (a->realtime < b->realtime) return -1; else if (a->realtime > b->realtime) return 1; else if (a->have_seqnum && b->have_seqnum) return memcmp(&a->seqnum_id, &b->seqnum_id, 16); else return strcmp(a->filename, b->filename); }
int main(int argc, char *argv[]) { sd_id128_t id, id2; char t[33]; _cleanup_free_ char *b = NULL; assert_se(sd_id128_randomize(&id) == 0); printf("random: %s\n", sd_id128_to_string(id, t)); assert_se(sd_id128_from_string(t, &id2) == 0); assert_se(sd_id128_equal(id, id2)); if (sd_booted() > 0) { assert_se(sd_id128_get_machine(&id) == 0); printf("machine: %s\n", sd_id128_to_string(id, t)); assert_se(sd_id128_get_boot(&id) == 0); printf("boot: %s\n", sd_id128_to_string(id, t)); } printf("waldi: %s\n", sd_id128_to_string(ID128_WALDI, t)); assert_se(streq(t, STR_WALDI)); assert_se(asprintf(&b, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 32); printf("waldi2: %s\n", b); assert_se(streq(t, b)); assert_se(sd_id128_from_string(UUID_WALDI, &id) >= 0); assert_se(sd_id128_equal(id, ID128_WALDI)); assert_se(sd_id128_from_string("", &id) < 0); assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f101", &id) < 0); assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f10-", &id) < 0); assert_se(sd_id128_from_string("01020304-0506-0708-090a0b0c0d0e0f10", &id) < 0); assert_se(sd_id128_from_string("010203040506-0708-090a-0b0c0d0e0f10", &id) < 0); assert_se(id128_is_valid(STR_WALDI)); assert_se(id128_is_valid(UUID_WALDI)); assert_se(!id128_is_valid("")); assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f101")); assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f10-")); assert_se(!id128_is_valid("01020304-0506-0708-090a0b0c0d0e0f10")); assert_se(!id128_is_valid("010203040506-0708-090a-0b0c0d0e0f10")); return 0; }
static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) { _cleanup_free_ char *opath = NULL; sd_id128_t ouuid; int r; r = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL); if (r < 0) return false; if (!sd_id128_equal(uuid, ouuid)) return false; if (!streq_ptr(path, opath)) return false; return true; }
static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) { char *opath = NULL; sd_id128_t ouuid; int err; bool same = false; err = efi_get_boot_option(id, NULL, &ouuid, &opath, NULL); if (err < 0) return false; if (!sd_id128_equal(uuid, ouuid)) goto finish; if (!streq_ptr(path, opath)) goto finish; same = true; finish: return same; }
static int condition_test_host(Condition *c) { _cleanup_free_ char *h = NULL; sd_id128_t x, y; int r; assert(c); assert(c->parameter); assert(c->type == CONDITION_HOST); if (sd_id128_from_string(c->parameter, &x) >= 0) { r = sd_id128_get_machine(&y); if (r < 0) return r; return sd_id128_equal(x, y); } h = gethostname_malloc(); if (!h) return -ENOMEM; return fnmatch(c->parameter, h, FNM_CASEFOLD) == 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; }
int main(int argc, char *argv[]) { int r; sd_journal *j = NULL; unsigned line = 0; bool need_seek = false; sd_id128_t previous_boot_id; bool previous_boot_id_valid = false; bool have_pager; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; if (arg_new_id128) { r = generate_new_id128(); goto finish; } #ifdef HAVE_ACL if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0) log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off."); #endif if (arg_directory) r = sd_journal_open_directory(&j, arg_directory, 0); else r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0); if (r < 0) { log_error("Failed to open journal: %s", strerror(-r)); goto finish; } if (arg_print_header) { journal_print_header(j); r = 0; goto finish; } r = add_this_boot(j); if (r < 0) goto finish; r = add_matches(j, argv + optind); if (r < 0) goto finish; if (!arg_quiet) { usec_t start, end; char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX]; r = sd_journal_get_cutoff_realtime_usec(j, &start, &end); if (r < 0) { log_error("Failed to get cutoff: %s", strerror(-r)); goto finish; } if (r > 0) { if (arg_follow) printf("Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start)); else printf("Logs begin at %s, end at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start), format_timestamp(end_buf, sizeof(end_buf), end)); } } if (arg_lines >= 0) { r = sd_journal_seek_tail(j); if (r < 0) { log_error("Failed to seek to tail: %s", strerror(-r)); goto finish; } r = sd_journal_previous_skip(j, arg_lines); } else { r = sd_journal_seek_head(j); if (r < 0) { log_error("Failed to seek to head: %s", strerror(-r)); goto finish; } r = sd_journal_next(j); } if (r < 0) { log_error("Failed to iterate through journal: %s", strerror(-r)); goto finish; } have_pager = !arg_no_pager && !arg_follow; if (have_pager) { columns(); pager_open(); } if (arg_output == OUTPUT_JSON) { fputc('[', stdout); fflush(stdout); } for (;;) { for (;;) { sd_id128_t boot_id; int flags = (arg_show_all*OUTPUT_SHOW_ALL | have_pager*OUTPUT_FULL_WIDTH); if (need_seek) { r = sd_journal_next(j); if (r < 0) { log_error("Failed to iterate through journal: %s", strerror(-r)); goto finish; } } if (r == 0) break; r = sd_journal_get_monotonic_usec(j, NULL, &boot_id); if (r >= 0) { if (previous_boot_id_valid && !sd_id128_equal(boot_id, previous_boot_id)) printf(ANSI_HIGHLIGHT_ON "----- Reboot -----" ANSI_HIGHLIGHT_OFF "\n"); previous_boot_id = boot_id; previous_boot_id_valid = true; } line ++; r = output_journal(j, arg_output, line, 0, flags); if (r < 0) goto finish; need_seek = true; } if (!arg_follow) break; r = sd_journal_wait(j, (uint64_t) -1); if (r < 0) { log_error("Couldn't wait for log event: %s", strerror(-r)); goto finish; } } if (arg_output == OUTPUT_JSON) fputs("\n]\n", stdout); finish: if (j) sd_journal_close(j); pager_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int show_status(char **args, unsigned n) { char buf[64]; struct boot_info *info; int err; err = boot_info_new(&info); if (err < 0) return -ENOMEM; err = boot_info_query(info); printf("System:\n"); printf(" Machine ID: %s\n", sd_id128_to_string(info->machine_id, buf)); printf(" Boot ID: %s\n", sd_id128_to_string(info->boot_id, buf)); if (info->fw_type) printf(" Firmware: %s (%s)\n", info->fw_type, strna(info->fw_info)); if (info->fw_secure_boot >= 0) printf(" Secure Boot: %s\n", info->fw_secure_boot ? "enabled" : "disabled"); if (info->fw_secure_boot_setup_mode >= 0) printf(" Setup Mode: %s\n", info->fw_secure_boot_setup_mode ? "setup" : "user"); printf("\n"); if (info->fw_entry_active >= 0) { printf("Selected Firmware Entry:\n"); printf(" Title: %s\n", strna(info->fw_entries[info->fw_entry_active].title)); if (!sd_id128_equal(info->fw_entries[info->fw_entry_active].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(info->fw_entries[info->fw_entry_active].part_uuid)); else printf(" Partition: n/a\n"); if (info->fw_entries[info->fw_entry_active].path) printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), info->fw_entries[info->fw_entry_active].path); } printf("\n"); if (info->loader) { printf("Boot Loader:\n"); printf(" Product: %s\n", info->loader); if (!sd_id128_equal(info->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(info->loader_part_uuid)); else printf(" Partition: n/a\n"); printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(info->loader_image_path)); printf("\n"); if (info->loader_entry_active >= 0) { printf("Selected Boot Loader Entry:\n"); printf(" Title: %s\n", strna(info->loader_entries[info->loader_entry_active].title)); printf(" File: %s\n", info->loader_entries[info->loader_entry_active].path); if (info->loader_options_added) printf(" Options: %s\n", info->loader_options_added); } } else printf("No suitable data is provided by the boot manager. See:\n" " http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface\n" " http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec\n" "for details.\n"); printf("\n"); boot_info_free(info); return err; }
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret) { #ifdef HAVE_BLKID sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL; _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; bool is_gpt, is_mbr, generic_rw, multiple_generic = false; _cleanup_udev_device_unref_ struct udev_device *d = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *generic_node = NULL; const char *pttype = NULL, *usage = NULL; struct udev_list_entry *first, *item; blkid_partlist pl; int r, generic_nr; struct stat st; unsigned i; assert(fd >= 0); assert(ret); assert(root_hash || root_hash_size == 0); /* Probes a disk image, and returns information about what it found in *ret. * * Returns -ENOPKG if no suitable partition table or file system could be found. * Returns -EADDRNOTAVAIL if a root hash was specified but no matching root/verity partitions found. */ if (root_hash) { /* If a root hash is supplied, then we use the root partition that has a UUID that match the first * 128bit of the root hash. And we use the verity partition that has a UUID that match the final * 128bit. */ if (root_hash_size < sizeof(sd_id128_t)) return -EINVAL; memcpy(&root_uuid, root_hash, sizeof(sd_id128_t)); memcpy(&verity_uuid, (const uint8_t*) root_hash + root_hash_size - sizeof(sd_id128_t), sizeof(sd_id128_t)); if (sd_id128_is_null(root_uuid)) return -EINVAL; if (sd_id128_is_null(verity_uuid)) return -EINVAL; } if (fstat(fd, &st) < 0) return -errno; if (!S_ISBLK(st.st_mode)) return -ENOTBLK; b = blkid_new_probe(); if (!b) return -ENOMEM; errno = 0; r = blkid_probe_set_device(b, fd, 0, 0); if (r != 0) { if (errno == 0) return -ENOMEM; return -errno; } blkid_probe_enable_superblocks(b, 1); blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE); 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) { log_debug("Failed to identify any partition table."); return -ENOPKG; } if (r != 0) { if (errno == 0) return -EIO; return -errno; } m = new0(DissectedImage, 1); if (!m) return -ENOMEM; (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL); if (STRPTR_IN_SET(usage, "filesystem", "crypto")) { _cleanup_free_ char *t = NULL, *n = NULL; const char *fstype = NULL; /* OK, we have found a file system, that's our root partition then. */ (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); if (fstype) { t = strdup(fstype); if (!t) return -ENOMEM; } if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) return -ENOMEM; m->partitions[PARTITION_ROOT] = (DissectedPartition) { .found = true, .rw = true, .partno = -1, .architecture = _ARCHITECTURE_INVALID, .fstype = t, .node = n, }; t = n = NULL; m->encrypted = streq(fstype, "crypto_LUKS"); *ret = m; m = NULL; return 0; } (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); if (!pttype) return -ENOPKG; is_gpt = streq_ptr(pttype, "gpt"); is_mbr = streq_ptr(pttype, "dos"); if (!is_gpt && !is_mbr) return -ENOPKG; errno = 0; pl = blkid_probe_get_partitions(b); if (!pl) { if (errno == 0) return -ENOMEM; return -errno; } udev = udev_new(); if (!udev) return -errno; d = udev_device_new_from_devnum(udev, 'b', st.st_rdev); if (!d) return -ENOMEM; for (i = 0;; i++) { int n, z; if (i >= 10) { log_debug("Kernel partitions never appeared."); return -ENXIO; } e = udev_enumerate_new(udev); if (!e) return -errno; r = udev_enumerate_add_match_parent(e, d); if (r < 0) return r; r = udev_enumerate_scan_devices(e); if (r < 0) return r; /* Count the partitions enumerated by the kernel */ n = 0; first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) n++; /* Count the partitions enumerated by blkid */ z = blkid_partlist_numof_partitions(pl); if (n == z + 1) break; if (n > z + 1) { log_debug("blkid and kernel partition list do not match."); return -EIO; } if (n < z + 1) { unsigned j; /* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running * or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a * synchronous call that waits until probing is complete. */ for (j = 0; j < 20; j++) { r = ioctl(fd, BLKRRPART, 0); if (r < 0) r = -errno; if (r >= 0 || r != -EBUSY) break; /* If something else has the device open, such as an udev rule, the ioctl will return * EBUSY. Since there's no way to wait until it isn't busy anymore, let's just wait a * bit, and try again. * * This is really something they should fix in the kernel! */ usleep(50 * USEC_PER_MSEC); } if (r < 0) return r; } e = udev_enumerate_unref(e); } 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; blkid_partition pp; const char *node; dev_t qn; int nr; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!q) return -errno; qn = udev_device_get_devnum(q); if (major(qn) == 0) continue; if (st.st_rdev == qn) continue; node = udev_device_get_devnode(q); if (!node) continue; pp = blkid_partlist_devno_to_partition(pl, qn); if (!pp) continue; flags = blkid_partition_get_flags(pp); nr = blkid_partition_get_partno(pp); if (nr < 0) continue; if (is_gpt) { int designator = _PARTITION_DESIGNATOR_INVALID, architecture = _ARCHITECTURE_INVALID; const char *stype, *sid, *fstype = NULL; sd_id128_t type_id, id; bool rw = true; if (flags & GPT_FLAG_NO_AUTO) continue; sid = blkid_partition_get_uuid(pp); if (!sid) continue; if (sd_id128_from_string(sid, &id) < 0) continue; stype = blkid_partition_get_type_string(pp); if (!stype) continue; if (sd_id128_from_string(stype, &type_id) < 0) continue; if (sd_id128_equal(type_id, GPT_HOME)) { designator = PARTITION_HOME; rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_SRV)) { designator = PARTITION_SRV; rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ESP)) { designator = PARTITION_ESP; fstype = "vfat"; } #ifdef GPT_ROOT_NATIVE else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) { /* If a root ID is specified, ignore everything but the root id */ if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) continue; designator = PARTITION_ROOT; architecture = native_architecture(); rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) { m->can_verity = true; /* Ignore verity unless a root hash is specified */ if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id)) continue; designator = PARTITION_ROOT_VERITY; fstype = "DM_verity_hash"; architecture = native_architecture(); rw = false; } #endif #ifdef GPT_ROOT_SECONDARY else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) { /* If a root ID is specified, ignore everything but the root id */ if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) continue; designator = PARTITION_ROOT_SECONDARY; architecture = SECONDARY_ARCHITECTURE; rw = !(flags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) { m->can_verity = true; /* Ignore verity unless root has is specified */ if (sd_id128_is_null(verity_uuid) || !sd_id128_equal(verity_uuid, id)) continue; designator = PARTITION_ROOT_SECONDARY_VERITY; fstype = "DM_verity_hash"; architecture = SECONDARY_ARCHITECTURE; rw = false; } #endif else if (sd_id128_equal(type_id, GPT_SWAP)) { designator = PARTITION_SWAP; fstype = "swap"; } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) { if (generic_node) multiple_generic = true; else { generic_nr = nr; generic_rw = !(flags & GPT_FLAG_READ_ONLY); generic_node = strdup(node); if (!generic_node) return -ENOMEM; } } if (designator != _PARTITION_DESIGNATOR_INVALID) { _cleanup_free_ char *t = NULL, *n = NULL; /* First one wins */ if (m->partitions[designator].found) continue; if (fstype) { t = strdup(fstype); if (!t) return -ENOMEM; } n = strdup(node); if (!n) return -ENOMEM; m->partitions[designator] = (DissectedPartition) { .found = true, .partno = nr, .rw = rw, .architecture = architecture, .node = n, .fstype = t, }; n = t = NULL; } } else if (is_mbr) {
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; uint64_t psize = 0; unsigned int i; int q; int r; if (argv[optind]) { 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)) { fprintf(stderr, "Unknown operation %s\n", argv[optind]); r = -EINVAL; goto finish; } } if (!arg_path) arg_path = "/boot"; if (geteuid() != 0) { fprintf(stderr, "Need to be root.\n"); r = -EPERM; goto finish; } r = verify_esp(arg_path, &part, &pstart, &psize, &uuid); if (r == -ENODEV && !arg_path) fprintf(stderr, "You might want to use --path= to indicate the path to your ESP, in case it is not mounted to /boot.\n"); if (r < 0) goto finish; 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 = {}; efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareType", &fw_type); efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderFirmwareInfo", &fw_info); efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &loader); if (efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderImageIdentifier", &loader_path) > 0) efi_tilt_backslashes(loader_path); efi_loader_get_device_part_uuid(&loader_part_uuid); printf("System:\n"); printf(" Firmware: %s (%s)\n", fw_type, strna(fw_info)); printf(" Secure Boot: %s\n", is_efi_secure_boot() ? "enabled" : "disabled"); printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "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", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path)); printf("\n"); r = status_binaries(arg_path, uuid); if (r < 0) goto finish; 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) goto finish; if (arg_action == ACTION_INSTALL) install_loader_config(arg_path); 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; } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int enumerate_partitions(dev_t devnum) { _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; _cleanup_udev_device_unref_ struct udev_device *d = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *home = NULL, *srv = NULL; struct udev_list_entry *first, *item; struct udev_device *parent = NULL; const char *node, *pttype, *devtype; int home_nr = -1, srv_nr = -1; blkid_partlist pl; int r, k; dev_t pn; udev = udev_new(); if (!udev) return log_oom(); d = udev_device_new_from_devnum(udev, 'b', devnum); if (!d) return log_oom(); parent = udev_device_get_parent(d); if (!parent) return log_oom(); /* Does it have a devtype? */ devtype = udev_device_get_devtype(parent); if (!devtype) return 0; /* Is this a disk or a partition? We only care for disks... */ if (!streq(devtype, "disk")) return 0; /* Does it have a device node? */ node = udev_device_get_devnode(parent); if (!node) return 0; log_debug("Root device %s.", node); pn = udev_device_get_devnum(parent); if (major(pn) == 0) return 0; errno = 0; b = blkid_new_probe_from_filename(node); if (!b) { if (errno == 0) return log_oom(); log_error("Failed allocate prober: %m"); return -errno; } blkid_probe_enable_superblocks(b, 1); blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); 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) { if (errno == 0) errno = EIO; log_error("Failed to probe %s: %m", node); return -errno; } errno = 0; r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); if (r != 0) { if (errno == 0) errno = EIO; log_error("Failed to determine partition table type of %s: %m", node); return -errno; } /* We only do this all for GPT... */ if (!streq_ptr(pttype, "gpt")) return 0; errno = 0; pl = blkid_probe_get_partitions(b); if (!pl) { if (errno == 0) return log_oom(); log_error("Failed to list partitions of %s: %m", node); return -errno; } e = udev_enumerate_new(udev); if (!e) return log_oom(); r = udev_enumerate_add_match_parent(e, parent); if (r < 0) return log_oom(); r = udev_enumerate_add_match_subsystem(e, "block"); if (r < 0) return log_oom(); r = udev_enumerate_scan_devices(e); if (r < 0) { log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r)); return r; } first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) { _cleanup_udev_device_unref_ struct udev_device *q; const char *stype, *subnode; sd_id128_t type_id; blkid_partition pp; dev_t qn; int nr; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!q) continue; qn = udev_device_get_devnum(q); if (major(qn) == 0) continue; if (qn == devnum) continue; if (qn == pn) continue; subnode = udev_device_get_devnode(q); if (!subnode) continue; pp = blkid_partlist_devno_to_partition(pl, qn); if (!pp) continue; nr = blkid_partition_get_partno(pp); if (nr < 0) continue; stype = blkid_partition_get_type_string(pp); if (!stype) continue; if (sd_id128_from_string(stype, &type_id) < 0) continue; if (sd_id128_equal(type_id, GPT_SWAP)) { k = add_swap(subnode); if (k < 0) r = k; } else if (sd_id128_equal(type_id, GPT_HOME)) { /* We only care for the first /home partition */ if (home && nr >= home_nr) continue; home_nr = nr; free(home); home = strdup(subnode); if (!home) return log_oom(); } else if (sd_id128_equal(type_id, GPT_SRV)) { /* We only care for the first /srv partition */ if (srv && nr >= srv_nr) continue; srv_nr = nr; free(srv); srv = strdup(node); if (!srv) return log_oom(); } }
int main(int argc, char *argv[]) { sd_id128_t id, id2; char t[33], q[37]; _cleanup_free_ char *b = NULL; _cleanup_close_ int fd = -1; assert_se(sd_id128_randomize(&id) == 0); printf("random: %s\n", sd_id128_to_string(id, t)); assert_se(sd_id128_from_string(t, &id2) == 0); assert_se(sd_id128_equal(id, id2)); if (sd_booted() > 0) { assert_se(sd_id128_get_machine(&id) == 0); printf("machine: %s\n", sd_id128_to_string(id, t)); assert_se(sd_id128_get_boot(&id) == 0); printf("boot: %s\n", sd_id128_to_string(id, t)); } printf("waldi: %s\n", sd_id128_to_string(ID128_WALDI, t)); assert_se(streq(t, STR_WALDI)); assert_se(asprintf(&b, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 32); printf("waldi2: %s\n", b); assert_se(streq(t, b)); printf("waldi3: %s\n", id128_to_uuid_string(ID128_WALDI, q)); assert_se(streq(q, UUID_WALDI)); b = mfree(b); assert_se(asprintf(&b, ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36); printf("waldi4: %s\n", b); assert_se(streq(q, b)); assert_se(sd_id128_from_string(STR_WALDI, &id) >= 0); assert_se(sd_id128_equal(id, ID128_WALDI)); assert_se(sd_id128_from_string(UUID_WALDI, &id) >= 0); assert_se(sd_id128_equal(id, ID128_WALDI)); assert_se(sd_id128_from_string("", &id) < 0); assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f101", &id) < 0); assert_se(sd_id128_from_string("01020304-0506-0708-090a-0b0c0d0e0f10-", &id) < 0); assert_se(sd_id128_from_string("01020304-0506-0708-090a0b0c0d0e0f10", &id) < 0); assert_se(sd_id128_from_string("010203040506-0708-090a-0b0c0d0e0f10", &id) < 0); assert_se(id128_is_valid(STR_WALDI)); assert_se(id128_is_valid(UUID_WALDI)); assert_se(!id128_is_valid("")); assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f101")); assert_se(!id128_is_valid("01020304-0506-0708-090a-0b0c0d0e0f10-")); assert_se(!id128_is_valid("01020304-0506-0708-090a0b0c0d0e0f10")); assert_se(!id128_is_valid("010203040506-0708-090a-0b0c0d0e0f10")); fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); /* First, write as UUID */ assert_se(sd_id128_randomize(&id) >= 0); assert_se(id128_write_fd(fd, ID128_UUID, id, false) >= 0); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); /* Second, write as plain */ assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(ftruncate(fd, 0) >= 0); assert_se(sd_id128_randomize(&id) >= 0); assert_se(id128_write_fd(fd, ID128_PLAIN, id, false) >= 0); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); /* Third, write plain without trailing newline */ assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(ftruncate(fd, 0) >= 0); assert_se(sd_id128_randomize(&id) >= 0); assert_se(write(fd, sd_id128_to_string(id, t), 32) == 32); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); /* Third, write UUID without trailing newline */ assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(ftruncate(fd, 0) >= 0); assert_se(sd_id128_randomize(&id) >= 0); assert_se(write(fd, id128_to_uuid_string(id, q), 36) == 36); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL); assert_se(lseek(fd, 0, SEEK_SET) == 0); assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); assert_se(sd_id128_equal(id, id2)); return 0; }
int journal_file_verify( JournalFile *f, const char *key, usec_t *first_contained, usec_t *last_validated, usec_t *last_contained, bool show_progress) { int r; Object *o; uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0; uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0; sd_id128_t entry_boot_id; bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false; uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0, n_tags = 0; usec_t last_usec = 0; int data_fd = -1, entry_fd = -1, entry_array_fd = -1; unsigned i; bool found_last = false; #ifdef HAVE_GCRYPT uint64_t last_tag = 0; #endif assert(f); if (key) { #ifdef HAVE_GCRYPT r = journal_file_parse_verification_key(f, key); if (r < 0) { log_error("Failed to parse seed."); return r; } #else return -ENOTSUP; #endif } else if (f->seal) return -ENOKEY; data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (data_fd < 0) { log_error_errno(errno, "Failed to create data file: %m"); r = -errno; goto fail; } entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_fd < 0) { log_error_errno(errno, "Failed to create entry file: %m"); r = -errno; goto fail; } entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_array_fd < 0) { log_error_errno(errno, "Failed to create entry array file: %m"); r = -errno; goto fail; } if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) { log_error("Cannot verify file with unknown extensions."); r = -ENOTSUP; goto fail; } for (i = 0; i < sizeof(f->header->reserved); i++) if (f->header->reserved[i] != 0) { error(offsetof(Header, reserved[i]), "Reserved field is non-zero"); r = -EBADMSG; goto fail; } /* First iteration: we go through all objects, verify the * superficial structure, headers, hashes. */ p = le64toh(f->header->header_size); for (;;) { /* Early exit if there are no objects in the file, at all */ if (le64toh(f->header->tail_object_offset) == 0) break; if (show_progress) draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec); r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); if (r < 0) { error(p, "Invalid object"); goto fail; } if (p > le64toh(f->header->tail_object_offset)) { error(offsetof(Header, tail_object_offset), "Invalid tail object pointer"); r = -EBADMSG; goto fail; } n_objects ++; r = journal_file_object_verify(f, p, o); if (r < 0) { error(p, "Invalid object contents: %s", strerror(-r)); goto fail; } if ((o->object.flags & OBJECT_COMPRESSED_XZ) && (o->object.flags & OBJECT_COMPRESSED_LZ4)) { error(p, "Objected with double compression"); r = -EINVAL; goto fail; } if ((o->object.flags & OBJECT_COMPRESSED_XZ) && !JOURNAL_HEADER_COMPRESSED_XZ(f->header)) { error(p, "XZ compressed object in file without XZ compression"); r = -EBADMSG; goto fail; } if ((o->object.flags & OBJECT_COMPRESSED_LZ4) && !JOURNAL_HEADER_COMPRESSED_LZ4(f->header)) { error(p, "LZ4 compressed object in file without LZ4 compression"); r = -EBADMSG; goto fail; } switch (o->object.type) { case OBJECT_DATA: r = write_uint64(data_fd, p); if (r < 0) goto fail; n_data++; break; case OBJECT_FIELD: n_fields++; break; case OBJECT_ENTRY: if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) { error(p, "First entry before first tag"); r = -EBADMSG; goto fail; } r = write_uint64(entry_fd, p); if (r < 0) goto fail; if (le64toh(o->entry.realtime) < last_tag_realtime) { error(p, "Older entry after newer tag"); r = -EBADMSG; goto fail; } if (!entry_seqnum_set && le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) { error(p, "Head entry sequence number incorrect"); r = -EBADMSG; goto fail; } if (entry_seqnum_set && entry_seqnum >= le64toh(o->entry.seqnum)) { error(p, "Entry sequence number out of synchronization"); r = -EBADMSG; goto fail; } entry_seqnum = le64toh(o->entry.seqnum); entry_seqnum_set = true; if (entry_monotonic_set && sd_id128_equal(entry_boot_id, o->entry.boot_id) && entry_monotonic > le64toh(o->entry.monotonic)) { error(p, "Entry timestamp out of synchronization"); r = -EBADMSG; goto fail; } entry_monotonic = le64toh(o->entry.monotonic); entry_boot_id = o->entry.boot_id; entry_monotonic_set = true; if (!entry_realtime_set && le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) { error(p, "Head entry realtime timestamp incorrect"); r = -EBADMSG; goto fail; } entry_realtime = le64toh(o->entry.realtime); entry_realtime_set = true; n_entries ++; break; case OBJECT_DATA_HASH_TABLE: if (n_data_hash_tables > 1) { error(p, "More than one data hash table"); r = -EBADMSG; goto fail; } if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) || le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) { error(p, "header fields for data hash table invalid"); r = -EBADMSG; goto fail; } n_data_hash_tables++; break; case OBJECT_FIELD_HASH_TABLE: if (n_field_hash_tables > 1) { error(p, "More than one field hash table"); r = -EBADMSG; goto fail; } if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) || le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) { error(p, "Header fields for field hash table invalid"); r = -EBADMSG; goto fail; } n_field_hash_tables++; break; case OBJECT_ENTRY_ARRAY: r = write_uint64(entry_array_fd, p); if (r < 0) goto fail; if (p == le64toh(f->header->entry_array_offset)) { if (found_main_entry_array) { error(p, "More than one main entry array"); r = -EBADMSG; goto fail; } found_main_entry_array = true; } n_entry_arrays++; break; case OBJECT_TAG: if (!JOURNAL_HEADER_SEALED(f->header)) { error(p, "Tag object in file without sealing"); r = -EBADMSG; goto fail; } if (le64toh(o->tag.seqnum) != n_tags + 1) { error(p, "Tag sequence number out of synchronization"); r = -EBADMSG; goto fail; } if (le64toh(o->tag.epoch) < last_epoch) { error(p, "Epoch sequence out of synchronization"); r = -EBADMSG; goto fail; } #ifdef HAVE_GCRYPT if (f->seal) { uint64_t q, rt; debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec; if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) { error(p, "tag/entry realtime timestamp out of synchronization"); r = -EBADMSG; goto fail; } /* OK, now we know the epoch. So let's now set * it, and calculate the HMAC for everything * since the last tag. */ r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch)); if (r < 0) goto fail; r = journal_file_hmac_start(f); if (r < 0) goto fail; if (last_tag == 0) { r = journal_file_hmac_put_header(f); if (r < 0) goto fail; q = le64toh(f->header->header_size); } else q = last_tag; while (q <= p) { r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o); if (r < 0) goto fail; r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q); if (r < 0) goto fail; q = q + ALIGN64(le64toh(o->object.size)); } /* Position might have changed, let's reposition things */ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); if (r < 0) goto fail; if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) { error(p, "Tag failed verification"); r = -EBADMSG; goto fail; } f->hmac_running = false; last_tag_realtime = rt; last_sealed_realtime = entry_realtime; } last_tag = p + ALIGN64(le64toh(o->object.size)); #endif last_epoch = le64toh(o->tag.epoch); n_tags ++; break; default: n_weird ++; } if (p == le64toh(f->header->tail_object_offset)) { found_last = true; break; } p = p + ALIGN64(le64toh(o->object.size)); }; if (!found_last && le64toh(f->header->tail_object_offset) != 0) { error(le64toh(f->header->tail_object_offset), "Tail object pointer dead"); r = -EBADMSG; goto fail; } if (n_objects != le64toh(f->header->n_objects)) { error(offsetof(Header, n_objects), "Object number mismatch"); r = -EBADMSG; goto fail; } if (n_entries != le64toh(f->header->n_entries)) { error(offsetof(Header, n_entries), "Entry number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_data) && n_data != le64toh(f->header->n_data)) { error(offsetof(Header, n_data), "Data number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) && n_fields != le64toh(f->header->n_fields)) { error(offsetof(Header, n_fields), "Field number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) && n_tags != le64toh(f->header->n_tags)) { error(offsetof(Header, n_tags), "Tag number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) && n_entry_arrays != le64toh(f->header->n_entry_arrays)) { error(offsetof(Header, n_entry_arrays), "Entry array number mismatch"); r = -EBADMSG; goto fail; } if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) { error(0, "Missing entry array"); r = -EBADMSG; goto fail; } if (entry_seqnum_set && entry_seqnum != le64toh(f->header->tail_entry_seqnum)) { error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum"); r = -EBADMSG; goto fail; } if (entry_monotonic_set && (!sd_id128_equal(entry_boot_id, f->header->boot_id) || entry_monotonic != le64toh(f->header->tail_entry_monotonic))) { error(0, "Invalid tail monotonic timestamp"); r = -EBADMSG; goto fail; } if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) { error(0, "Invalid tail realtime timestamp"); r = -EBADMSG; goto fail; } /* Second iteration: we follow all objects referenced from the * two entry points: the object hash table and the entry * array. We also check that everything referenced (directly * or indirectly) in the data hash table also exists in the * entry array, and vice versa. Note that we do not care for * unreferenced objects. We only care that everything that is * referenced is consistent. */ r = verify_entry_array(f, data_fd, n_data, entry_fd, n_entries, entry_array_fd, n_entry_arrays, &last_usec, show_progress); if (r < 0) goto fail; r = verify_hash_table(f, data_fd, n_data, entry_fd, n_entries, entry_array_fd, n_entry_arrays, &last_usec, show_progress); if (r < 0) goto fail; if (show_progress) flush_progress(); mmap_cache_close_fd(f->mmap, data_fd); mmap_cache_close_fd(f->mmap, entry_fd); mmap_cache_close_fd(f->mmap, entry_array_fd); safe_close(data_fd); safe_close(entry_fd); safe_close(entry_array_fd); if (first_contained) *first_contained = le64toh(f->header->head_entry_realtime); if (last_validated) *last_validated = last_sealed_realtime; if (last_contained) *last_contained = le64toh(f->header->tail_entry_realtime); return 0; fail: if (show_progress) flush_progress(); log_error("File corruption detected at %s:"OFSfmt" (of %llu bytes, %"PRIu64"%%).", f->path, p, (unsigned long long) f->last_stat.st_size, 100 * p / f->last_stat.st_size); if (data_fd >= 0) { mmap_cache_close_fd(f->mmap, data_fd); safe_close(data_fd); } if (entry_fd >= 0) { mmap_cache_close_fd(f->mmap, entry_fd); safe_close(entry_fd); } if (entry_array_fd >= 0) { mmap_cache_close_fd(f->mmap, entry_array_fd); safe_close(entry_array_fd); } return r; }
static void test_non_empty(void) { dual_timestamp ts; JournalFile *f; struct iovec iovec; static const char test[] = "TEST1=1", test2[] = "TEST2=2"; Object *o; uint64_t p; sd_id128_t fake_boot_id; char t[] = "/tmp/journal-XXXXXX"; test_setup_logging(LOG_DEBUG); assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, true, NULL, NULL, NULL, NULL, &f) == 0); assert_se(dual_timestamp_get(&ts)); assert_se(sd_id128_randomize(&fake_boot_id) == 0); iovec.iov_base = (void*) test; iovec.iov_len = strlen(test); assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0); iovec.iov_base = (void*) test2; iovec.iov_len = strlen(test2); assert_se(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL) == 0); iovec.iov_base = (void*) test; iovec.iov_len = strlen(test); assert_se(journal_file_append_entry(f, &ts, &fake_boot_id, &iovec, 1, NULL, NULL, NULL) == 0); #if HAVE_GCRYPT journal_file_append_tag(f); #endif journal_file_dump(f); assert_se(journal_file_next_entry(f, 0, DIRECTION_DOWN, &o, &p) == 1); assert_se(le64toh(o->entry.seqnum) == 1); assert_se(journal_file_next_entry(f, p, DIRECTION_DOWN, &o, &p) == 1); assert_se(le64toh(o->entry.seqnum) == 2); assert_se(journal_file_next_entry(f, p, DIRECTION_DOWN, &o, &p) == 1); assert_se(le64toh(o->entry.seqnum) == 3); assert_se(sd_id128_equal(o->entry.boot_id, fake_boot_id)); assert_se(journal_file_next_entry(f, p, DIRECTION_DOWN, &o, &p) == 0); assert_se(journal_file_next_entry(f, 0, DIRECTION_DOWN, &o, &p) == 1); assert_se(le64toh(o->entry.seqnum) == 1); assert_se(journal_file_find_data_object(f, test, strlen(test), NULL, &p) == 1); assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 1); assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 3); assert_se(journal_file_find_data_object(f, test2, strlen(test2), NULL, &p) == 1); assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 2); assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 2); assert_se(journal_file_find_data_object(f, "quux", 4, NULL, &p) == 0); assert_se(journal_file_move_to_entry_by_seqnum(f, 1, DIRECTION_DOWN, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 1); assert_se(journal_file_move_to_entry_by_seqnum(f, 3, DIRECTION_DOWN, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 3); assert_se(journal_file_move_to_entry_by_seqnum(f, 2, DIRECTION_DOWN, &o, NULL) == 1); assert_se(le64toh(o->entry.seqnum) == 2); assert_se(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0); journal_file_rotate(&f, true, (uint64_t) -1, true, NULL); journal_file_rotate(&f, true, (uint64_t) -1, true, NULL); (void) journal_file_close(f); log_info("Done..."); if (arg_keep) log_info("Not removing %s", t); else { journal_directory_vacuum(".", 3000000, 0, 0, NULL, true); assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } puts("------------------------------------------------------------"); }
int journal_file_fss_load(JournalFile *f) { int r, fd = -1; char *p = NULL; struct stat st; FSSHeader *m = NULL; sd_id128_t machine; assert(f); if (!f->seal) return 0; r = sd_id128_get_machine(&machine); if (r < 0) return r; if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss", SD_ID128_FORMAT_VAL(machine)) < 0) return -ENOMEM; fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (fd < 0) { if (errno != ENOENT) log_error_errno(errno, "Failed to open %s: %m", p); r = -errno; goto finish; } if (fstat(fd, &st) < 0) { r = -errno; goto finish; } if (st.st_size < (off_t) sizeof(FSSHeader)) { r = -ENODATA; goto finish; } m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0); if (m == MAP_FAILED) { m = NULL; r = -errno; goto finish; } if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) { r = -EBADMSG; goto finish; } if (m->incompatible_flags != 0) { r = -EPROTONOSUPPORT; goto finish; } if (le64toh(m->header_size) < sizeof(FSSHeader)) { r = -EBADMSG; goto finish; } if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(le16toh(m->fsprg_secpar))) { r = -EBADMSG; goto finish; } f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size); if ((uint64_t) st.st_size < f->fss_file_size) { r = -ENODATA; goto finish; } if (!sd_id128_equal(machine, m->machine_id)) { r = -EHOSTDOWN; goto finish; } if (le64toh(m->start_usec) <= 0 || le64toh(m->interval_usec) <= 0) { r = -EBADMSG; goto finish; } f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (f->fss_file == MAP_FAILED) { f->fss_file = NULL; r = -errno; goto finish; } f->fss_start_usec = le64toh(f->fss_file->start_usec); f->fss_interval_usec = le64toh(f->fss_file->interval_usec); f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size); f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size); r = 0; finish: if (m) munmap(m, PAGE_ALIGN(sizeof(FSSHeader))); safe_close(fd); free(p); return r; }
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; }
static void test_sequence_numbers(void) { char t[] = "/tmp/journal-seq-XXXXXX"; JournalFile *one, *two; uint64_t seqnum = 0; sd_id128_t seqnum_id; assert_se(mkdtemp(t)); assert_se(chdir(t) >= 0); assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &one) == 0); append_number(one, 1, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); assert(seqnum == 1); append_number(one, 2, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); assert(seqnum == 2); assert(one->header->state == STATE_ONLINE); assert(!sd_id128_equal(one->header->file_id, one->header->machine_id)); assert(!sd_id128_equal(one->header->file_id, one->header->boot_id)); assert(sd_id128_equal(one->header->file_id, one->header->seqnum_id)); memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t)); assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, one, &two) == 0); assert(two->header->state == STATE_ONLINE); assert(!sd_id128_equal(two->header->file_id, one->header->file_id)); assert(sd_id128_equal(one->header->machine_id, one->header->machine_id)); assert(sd_id128_equal(one->header->boot_id, one->header->boot_id)); assert(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id)); append_number(two, 3, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); assert(seqnum == 3); append_number(two, 4, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); assert(seqnum == 4); test_close(two); append_number(one, 5, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); assert(seqnum == 5); append_number(one, 6, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); assert(seqnum == 6); test_close(one); /* restart server */ seqnum = 0; assert_se(journal_file_open("two.journal", O_RDWR, 0, true, false, NULL, NULL, NULL, &two) == 0); assert(sd_id128_equal(two->header->seqnum_id, seqnum_id)); append_number(two, 7, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); assert(seqnum == 5); /* So..., here we have the same seqnum in two files with the * same seqnum_id. */ test_close(two); log_info("Done..."); if (arg_keep) log_info("Not removing %s", t); else { journal_directory_vacuum(".", 3000000, 0, 0, NULL); assert_se(rm_rf_dangerous(t, false, true, false) >= 0); } }
static int enumerate_partitions(dev_t devnum) { _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; _cleanup_udev_device_unref_ struct udev_device *d = NULL; _cleanup_blkid_free_probe_ blkid_probe b = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL; struct udev_list_entry *first, *item; struct udev_device *parent = NULL; const char *name, *node, *pttype, *devtype; int boot_nr = -1, home_nr = -1, srv_nr = -1; bool home_rw = true, srv_rw = true; blkid_partlist pl; int r, k; dev_t pn; udev = udev_new(); if (!udev) return log_oom(); d = udev_device_new_from_devnum(udev, 'b', devnum); if (!d) return log_oom(); name = udev_device_get_devnode(d); if (!name) name = udev_device_get_syspath(d); if (!name) { log_debug("Device %u:%u does not have a name, ignoring.", major(devnum), minor(devnum)); return 0; } parent = udev_device_get_parent(d); if (!parent) { log_debug("%s: not a partitioned device, ignoring.", name); return 0; } /* Does it have a devtype? */ devtype = udev_device_get_devtype(parent); if (!devtype) { log_debug("%s: parent doesn't have a device type, ignoring.", name); return 0; } /* Is this a disk or a partition? We only care for disks... */ if (!streq(devtype, "disk")) { log_debug("%s: parent isn't a raw disk, ignoring.", name); return 0; } /* Does it have a device node? */ node = udev_device_get_devnode(parent); if (!node) { log_debug("%s: parent device does not have device node, ignoring.", name); return 0; } log_debug("%s: root device %s.", name, node); pn = udev_device_get_devnum(parent); if (major(pn) == 0) return 0; errno = 0; b = blkid_new_probe_from_filename(node); if (!b) { if (errno == 0) return log_oom(); return log_error_errno(errno, "%s: failed to allocate prober: %m", node); } 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 == 1) return 0; /* no results */ else if (r == -2) { log_warning("%s: probe gave ambiguous results, ignoring", node); return 0; } else if (r != 0) return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node); errno = 0; r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); if (r != 0) return log_error_errno(errno ?: EIO, "%s: failed to determine partition table type: %m", node); /* We only do this all for GPT... */ if (!streq_ptr(pttype, "gpt")) { log_debug("%s: not a GPT partition table, ignoring.", node); return 0; } errno = 0; pl = blkid_probe_get_partitions(b); if (!pl) { if (errno == 0) return log_oom(); return log_error_errno(errno, "%s: failed to list partitions: %m", node); } e = udev_enumerate_new(udev); if (!e) return log_oom(); r = udev_enumerate_add_match_parent(e, parent); if (r < 0) return log_oom(); r = udev_enumerate_add_match_subsystem(e, "block"); if (r < 0) return log_oom(); r = udev_enumerate_scan_devices(e); if (r < 0) return log_error_errno(r, "%s: failed to enumerate partitions: %m", node); 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; dev_t qn; int nr; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); if (!q) continue; qn = udev_device_get_devnum(q); if (major(qn) == 0) continue; if (qn == devnum) continue; if (qn == pn) continue; subnode = udev_device_get_devnode(q); if (!subnode) continue; pp = blkid_partlist_devno_to_partition(pl, qn); if (!pp) continue; nr = blkid_partition_get_partno(pp); if (nr < 0) continue; stype = blkid_partition_get_type_string(pp); if (!stype) continue; if (sd_id128_from_string(stype, &type_id) < 0) continue; flags = blkid_partition_get_flags(pp); if (sd_id128_equal(type_id, GPT_SWAP)) { if (flags & GPT_FLAG_NO_AUTO) continue; if (flags & GPT_FLAG_READ_ONLY) { log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode); continue; } k = add_swap(subnode); if (k < 0) r = k; } else if (sd_id128_equal(type_id, GPT_ESP)) { /* We only care for the first /boot partition */ 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); if (r < 0) return log_oom(); } else if (sd_id128_equal(type_id, GPT_HOME)) { if (flags & GPT_FLAG_NO_AUTO) continue; /* We only care for the first /home partition */ if (home && nr >= home_nr) continue; home_nr = nr; home_rw = !(flags & GPT_FLAG_READ_ONLY), r = free_and_strdup(&home, subnode); if (r < 0) return log_oom(); } else if (sd_id128_equal(type_id, GPT_SRV)) { if (flags & GPT_FLAG_NO_AUTO) continue; /* We only care for the first /srv partition */ if (srv && nr >= srv_nr) continue; srv_nr = nr; srv_rw = !(flags & GPT_FLAG_READ_ONLY), r = free_and_strdup(&srv, subnode); if (r < 0) return log_oom(); } }
static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) { #if defined(GPT_ROOT_NATIVE) && defined(ENABLE_EFI) _cleanup_free_ char *root_id = NULL; bool found_esp = false; blkid_partlist pl; int i, nvals, r; assert(pr); /* Iterate through the partitions on this disk, and see if the * EFI ESP we booted from is on it. If so, find the first root * disk, and add a property indicating its partition UUID. */ errno = 0; pl = blkid_probe_get_partitions(pr); if (!pl) return errno ? -errno : -ENOMEM; nvals = blkid_partlist_numof_partitions(pl); for (i = 0; i < nvals; i++) { blkid_partition pp; const char *stype, *sid; sd_id128_t type; pp = blkid_partlist_get_partition(pl, i); if (!pp) continue; sid = blkid_partition_get_uuid(pp); if (!sid) continue; stype = blkid_partition_get_type_string(pp); if (!stype) continue; if (sd_id128_from_string(stype, &type) < 0) continue; if (sd_id128_equal(type, GPT_ESP)) { sd_id128_t id, esp; /* We found an ESP, let's see if it matches * the ESP we booted from. */ if (sd_id128_from_string(sid, &id) < 0) continue; r = efi_loader_get_device_part_uuid(&esp); if (r < 0) return r; if (sd_id128_equal(id, esp)) found_esp = true; } else if (sd_id128_equal(type, GPT_ROOT_NATIVE)) { /* We found a suitable root partition, let's * remember the first one. */ if (!root_id) { root_id = strdup(sid); if (!root_id) return -ENOMEM; } } } /* We found the ESP on this disk, and also found a root * partition, nice! Let's export its UUID */ if (found_esp && root_id) udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", root_id); #endif return 0; }
/** * 客户端和远程服务器的交互 */ void srv_bufferread_cb(struct bufferevent *bev, void *ptr) { size_t n = 0; CTL_HEAD head; struct evbuffer *input = bufferevent_get_input(bev); struct evbuffer *output = bufferevent_get_output(bev); if ( evbuffer_remove(input, &head, CTL_HEAD_LEN) != CTL_HEAD_LEN) { st_d_print("读取数据包头%d错误!", CTL_HEAD_LEN); return; } if (!sd_id128_equal(head.mach_uuid, cltopt.session_uuid)) { SYS_ABORT("服务端返回UUID校验失败:%s-%s", SD_ID128_CONST_STR(head.mach_uuid), SD_ID128_CONST_STR(cltopt.session_uuid)); } if (head.cmd == HD_CMD_ERROR) { st_d_error("SERVER RETURNED ERROR!"); exit(EXIT_SUCCESS); } if (head.cmd == HD_CMD_CONN_ACT) { P_PORTTRANS p_trans = sc_find_trans(head.extra_param); if (!p_trans) { SYS_ABORT("本地未找到连接信息:%d", head.extra_param); } bufferevent_enable(p_trans->local_bev, EV_READ|EV_WRITE); bufferevent_enable(p_trans->srv_bev, EV_READ|EV_WRITE); st_d_print("开始传输数据:%d", head.extra_param); } if (head.cmd == HD_CMD_END_TRANS) { P_PORTTRANS p_trans = sc_find_trans(head.extra_param); if (p_trans) { st_d_print("EXTRA CLOSE TRANS: %d", head.extra_param); sc_free_trans(p_trans); } } if (head.cmd == HD_CMD_SS5_ACT) { // OK,返回给本地程序告知可以开始传输了 // 这个绑定地址目前还没利用,主要是需要FTP这类需要带外传输另外连接端口的 char ret_msg[10] = "\x05\x00\x00\x01\x00\x00\x00\x00\x10\x10"; P_PORTTRANS p_trans = sc_find_trans(head.extra_param); if (!p_trans) { SYS_ABORT("本地SS5未找到连接信息:%d", head.extra_param); } bufferevent_enable(p_trans->local_bev, EV_READ|EV_WRITE); bufferevent_enable(p_trans->srv_bev, EV_READ|EV_WRITE); bufferevent_write(p_trans->local_bev, ret_msg, sizeof(ret_msg)); st_d_print("SS5准备传输数据:%d", head.extra_param); return; } if (head.cmd == HD_CMD_CONN) { assert(cltopt.C_TYPE == C_DAEMON); if (cltopt.C_TYPE == C_DAEMON) { sc_find_daemon_portmap(head.daemonport, 1); P_PORTTRANS p_trans = sc_create_trans(head.extra_param); p_trans->is_enc = 0; if (!p_trans) { st_d_error("本地无空闲TRANS!"); return; } /*建立本地连接*/ int local_fd = socket(AF_INET, SOCK_STREAM, 0); int reuseaddr_on = 1; if (setsockopt(local_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on)) == -1) { st_d_error("Reuse socket opt faile!\n"); return; } struct sockaddr_in local_srv; local_srv.sin_family = AF_INET; local_srv.sin_addr.s_addr = inet_addr("127.0.0.1"); local_srv.sin_port = htons(head.daemonport); if (connect(local_fd, (struct sockaddr *)&local_srv, sizeof(local_srv))) { st_d_error("连接本地端口%d失败!", head.daemonport); return; } else { st_d_print("连接本地端口%d OK!", head.daemonport); } /*建立服务器连接*/ int srv_fd = socket(AF_INET, SOCK_STREAM, 0); if(sc_connect_srv(srv_fd) != RET_YES) { st_d_error("连接服务器失败!"); return; } struct event_base *base = bufferevent_get_base(bev); evutil_make_socket_nonblocking(local_fd); struct bufferevent *local_bev = bufferevent_socket_new(base, local_fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(local_bev, bufferread_cb, NULL, bufferevent_cb, p_trans); //bufferevent_enable(local_bev, EV_READ|EV_WRITE); evutil_make_socket_nonblocking(srv_fd); struct bufferevent *srv_bev = bufferevent_socket_new(base, srv_fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(srv_bev, bufferread_cb, NULL, bufferevent_cb, p_trans); //bufferevent_enable(srv_bev, EV_READ|EV_WRITE); p_trans->l_port = head.extra_param; p_trans->local_bev = local_bev; p_trans->srv_bev = srv_bev; /* 向服务器报告连接请求 */ // 必须要发送CONN包,触发这个连接转移到线程池处理 CTL_HEAD ret_head; memset(&ret_head, 0, CTL_HEAD_LEN); ret_head.cmd = HD_CMD_CONN; ret_head.extra_param = p_trans->l_port; ret_head.mach_uuid = cltopt.session_uuid; ret_head.direct = DAEMON_USR; bufferevent_write(srv_bev, &ret_head, CTL_HEAD_LEN); st_d_print("DAEMON端准备OK!"); } } }