static int list_dependencies_print(const char *name, unsigned int level, unsigned int branches, bool last, struct unit_times *times, struct boot_times *boot) { unsigned int i; char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX]; for (i = level; i != 0; i--) printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERT : DRAW_TREE_SPACE)); printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH)); if (times) { if (times->time) printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED_ON, name, format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC), format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF); else if (times->activated > boot->userspace_time) printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC)); else printf("%s", name); } else printf("%s", name); printf("\n"); return 0; }
static int prompt_root_password(void) { const char *msg1, *msg2, *etc_shadow; int r; if (arg_root_password) return 0; if (!arg_prompt_root_password) return 0; etc_shadow = prefix_roota("/etc/shadow"); if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) return 0; print_welcome(); putchar('\n'); msg1 = strappenda(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): "); msg2 = strappenda(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: "); for (;;) { _cleanup_free_ char *a = NULL, *b = NULL; r = ask_password_tty(msg1, 0, false, NULL, &a); if (r < 0) { log_error("Failed to query root password: %s", strerror(-r)); return r; } if (isempty(a)) { log_warning("No password entered, skipping."); break; } r = ask_password_tty(msg2, 0, false, NULL, &b); if (r < 0) { log_error("Failed to query root password: %s", strerror(-r)); clear_string(a); return r; } if (!streq(a, b)) { log_error("Entered passwords did not match, please try again."); clear_string(a); clear_string(b); continue; } clear_string(b); arg_root_password = a; a = NULL; break; } return 0; }
static int notify_override_extended(const char *top, const char *bottom) { if (!(arg_flags & SHOW_EXTENDED)) return 0; printf("%s%s%s %s %s %s\n", ansi_highlight(), "[EXTENDED]", ansi_normal(), top, draw_special_char(DRAW_ARROW), bottom); return 1; }
static int notify_override_overridden(const char *top, const char *bottom) { if (!(arg_flags & SHOW_OVERRIDDEN)) return 0; printf("%s%s%s %s %s %s\n", ansi_highlight(), "[OVERRIDDEN]", ansi_normal(), top, draw_special_char(DRAW_ARROW), bottom); return 1; }
static int notify_override_equivalent(const char *top, const char *bottom) { if (!(arg_flags & SHOW_EQUIVALENT)) return 0; printf("%s%s%s %s %s %s\n", ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(), top, draw_special_char(DRAW_ARROW), bottom); return 1; }
static int notify_override_redirected(const char *top, const char *bottom) { if (!(arg_flags & SHOW_REDIRECTED)) return 0; printf("%s%s%s %s %s %s\n", ansi_highlight(), "[REDIRECTED]", ansi_highlight_off(), top, draw_special_char(DRAW_ARROW), bottom); return 1; }
static int notify_override_masked(const char *top, const char *bottom) { if (!(arg_flags & SHOW_MASKED)) return 0; printf("%s%s%s %s %s %s\n", ansi_lightred(), "[MASKED]", ansi_highlight_off(), top, draw_special_char(DRAW_ARROW), bottom); return 1; }
static int prompt_loop(const char *text, char **l, bool (*is_valid)(const char *name), char **ret) { int r; assert(text); assert(is_valid); assert(ret); for (;;) { _cleanup_free_ char *p = NULL; unsigned u; r = ask_string(&p, "%s %s (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET), text); if (r < 0) { log_error("Failed to query user: %s", strerror(-r)); return r; } if (isempty(p)) { log_warning("No data entered, skipping."); return 0; } r = safe_atou(p, &u); if (r >= 0) { char *c; if (u <= 0 || u > strv_length(l)) { log_error("Specified entry number out of range."); continue; } log_info("Selected '%s'.", l[u-1]); c = strdup(l[u-1]); if (!c) return log_oom(); free(*ret); *ret = c; return 0; } if (!is_valid(p)) { log_error("Entered data invalid."); continue; } free(*ret); *ret = p; p = 0; return 0; } }
int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) { _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; struct udev_list_entry *first = NULL; int r; if (n_columns <= 0) n_columns = columns(); if (!prefix) prefix = ""; if (isempty(seat)) seat = "seat0"; udev = udev_new(); if (!udev) return -ENOMEM; e = udev_enumerate_new(udev); if (!e) return -ENOMEM; if (!streq(seat, "seat0")) r = udev_enumerate_add_match_tag(e, seat); else r = udev_enumerate_add_match_tag(e, "seat"); if (r < 0) return r; r = udev_enumerate_add_match_is_initialized(e); if (r < 0) return r; r = udev_enumerate_scan_devices(e); if (r < 0) return r; first = udev_enumerate_get_list_entry(e); if (first) show_sysfs_one(udev, seat, &first, "/", prefix, n_columns); else printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), "(none)"); return r; }
static int prompt_hostname(void) { int r; if (arg_hostname) return 0; if (!arg_prompt_hostname) return 0; print_welcome(); putchar('\n'); for (;;) { _cleanup_free_ char *h = NULL; r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET)); if (r < 0) return log_error_errno(r, "Failed to query hostname: %m"); if (isempty(h)) { log_warning("No hostname entered, skipping."); break; } if (!hostname_is_valid(h, true)) { log_error("Specified hostname invalid."); continue; } /* Get rid of the trailing dot that we allow, but don't want to see */ arg_hostname = hostname_cleanup(h); h = NULL; break; } return 0; }
static int prompt_hostname(void) { int r; if (arg_hostname) return 0; if (!arg_prompt_hostname) return 0; print_welcome(); putchar('\n'); for (;;) { _cleanup_free_ char *h = NULL; r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET)); if (r < 0) { log_error("Failed to query hostname: %s", strerror(-r)); return r; } if (isempty(h)) { log_warning("No hostname entered, skipping."); break; } if (!hostname_is_valid(h)) { log_error("Specified hostname invalid."); continue; } arg_hostname = h; h = NULL; break; } return 0; }
static int show_sysfs_one( struct udev *udev, const char *seat, struct udev_list_entry **item, const char *sub, const char *prefix, unsigned n_columns) { assert(udev); assert(seat); assert(item); assert(prefix); while (*item) { struct udev_list_entry *next, *lookahead; struct udev_device *d; const char *sn, *name, *sysfs, *subsystem, *sysname; char *l, *k; bool is_master; sysfs = udev_list_entry_get_name(*item); if (!path_startswith(sysfs, sub)) return 0; d = udev_device_new_from_syspath(udev, sysfs); if (!d) { *item = udev_list_entry_get_next(*item); continue; } sn = udev_device_get_property_value(d, "ID_SEAT"); if (isempty(sn)) sn = "seat0"; /* Explicitly also check for tag 'seat' here */ if (!streq(seat, sn) || !udev_device_has_tag(d, "seat")) { udev_device_unref(d); *item = udev_list_entry_get_next(*item); continue; } is_master = udev_device_has_tag(d, "seat-master"); name = udev_device_get_sysattr_value(d, "name"); if (!name) name = udev_device_get_sysattr_value(d, "id"); subsystem = udev_device_get_subsystem(d); sysname = udev_device_get_sysname(d); /* Look if there's more coming after this */ lookahead = next = udev_list_entry_get_next(*item); while (lookahead) { const char *lookahead_sysfs; lookahead_sysfs = udev_list_entry_get_name(lookahead); if (path_startswith(lookahead_sysfs, sub) && !path_startswith(lookahead_sysfs, sysfs)) { struct udev_device *lookahead_d; lookahead_d = udev_device_new_from_syspath(udev, lookahead_sysfs); if (lookahead_d) { const char *lookahead_sn; bool found; lookahead_sn = udev_device_get_property_value(d, "ID_SEAT"); if (isempty(lookahead_sn)) lookahead_sn = "seat0"; found = streq(seat, lookahead_sn) && udev_device_has_tag(lookahead_d, "seat"); udev_device_unref(lookahead_d); if (found) break; } } lookahead = udev_list_entry_get_next(lookahead); } k = ellipsize(sysfs, n_columns, 20); printf("%s%s%s\n", prefix, draw_special_char(lookahead ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), k ? k : sysfs); free(k); if (asprintf(&l, "%s%s:%s%s%s%s", is_master ? "[MASTER] " : "", subsystem, sysname, name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0) { udev_device_unref(d); return -ENOMEM; } k = ellipsize(l, n_columns, 70); printf("%s%s%s\n", prefix, lookahead ? draw_special_char(DRAW_TREE_VERT) : " ", k ? k : l); free(k); free(l); *item = next; if (*item) { char *p; p = strappend(prefix, lookahead ? draw_special_char(DRAW_TREE_VERT) : " "); show_sysfs_one(udev, seat, item, sysfs, p ? p : prefix, n_columns - 2); free(p); } udev_device_unref(d); } return 0; }
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; }
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", draw_special_char(DRAW_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; }
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_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const char *toppath, const char *drop) { _cleanup_free_ char *unit = NULL; _cleanup_free_ char *path = NULL; _cleanup_strv_free_ char **list = NULL; char **file; char *c; int r; assert(!endswith(drop, "/")); path = strjoin(toppath, "/", drop, NULL); if (!path) return -ENOMEM; log_debug("Looking at %s", path); unit = strdup(drop); if (!unit) return -ENOMEM; c = strrchr(unit, '.'); if (!c) return -EINVAL; *c = 0; r = get_files_in_directory(path, &list); if (r < 0) return log_error_errno(r, "Failed to enumerate %s: %m", path); STRV_FOREACH(file, list) { Hashmap *h; int k; char *p; char *d; if (!endswith(*file, ".conf")) continue; p = strjoin(path, "/", *file, NULL); if (!p) return -ENOMEM; d = p + strlen(toppath) + 1; log_debug("Adding at top: %s %s %s", d, draw_special_char(DRAW_ARROW), p); k = hashmap_put(top, d, p); if (k >= 0) { p = strdup(p); if (!p) return -ENOMEM; d = p + strlen(toppath) + 1; } else if (k != -EEXIST) { free(p); return k; } log_debug("Adding at bottom: %s %s %s", d, draw_special_char(DRAW_ARROW), p); free(hashmap_remove(bottom, d)); k = hashmap_put(bottom, d, p); if (k < 0) { free(p); return k; } h = hashmap_get(drops, unit); if (!h) { h = hashmap_new(&string_hash_ops); if (!h) return -ENOMEM; hashmap_put(drops, unit, h); unit = strdup(unit); if (!unit) return -ENOMEM; } p = strdup(p); if (!p) return -ENOMEM; log_debug("Adding to drops: %s %s %s %s %s", unit, draw_special_char(DRAW_ARROW), basename(p), draw_special_char(DRAW_ARROW), p); k = hashmap_put(h, basename(p), p); if (k < 0) { free(p); if (k != -EEXIST) return k; } }