From: Lennart Poettering Date: Fri, 19 Sep 2025 13:02:51 +0000 (+0200) Subject: homectl: port to prompt_loop() X-Git-Tag: v259-rc1~402^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f233132a67a4c2c6dff053afac2385f570e8e3fe;p=thirdparty%2Fsystemd.git homectl: port to prompt_loop() --- diff --git a/src/home/homectl.c b/src/home/homectl.c index 199cb395379..8c99120ea61 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -16,6 +16,7 @@ #include "capability-list.h" #include "capability-util.h" #include "cgroup-util.h" +#include "chase.h" #include "creds-util.h" #include "dirent-util.h" #include "dns-domain.h" @@ -2697,6 +2698,8 @@ static int prompt_groups(const char *username, char ***ret_groups) { return 0; } + putchar('\n'); + _cleanup_strv_free_ char **available = NULL, **groups = NULL; for (;;) { strv_sort_uniq(groups); @@ -2713,7 +2716,7 @@ static int prompt_groups(const char *username, char ***ret_groups) { r = ask_string_full(&s, group_completion_callback, &available, "%s Please enter an auxiliary group for user %s (empty to continue, \"list\" to list available groups): ", - glyph(GLYPH_TRIANGULAR_BULLET), username); + glyph(GLYPH_LABEL), username); if (r < 0) return log_error_errno(r, "Failed to query user for auxiliary group: %m"); @@ -2787,9 +2790,32 @@ static int prompt_groups(const char *username, char ***ret_groups) { return 0; } -static int prompt_shell(const char *username, char **ret_shell) { +static int shell_is_ok(const char *path, void *userdata) { int r; + assert(path); + + if (!valid_shell(path)) { + log_error("String '%s' is not a valid path to a shell, refusing.", path); + return false; + } + + r = chase_and_access(path, /* root= */ NULL, CHASE_MUST_BE_REGULAR, X_OK, /* ret_path= */ NULL) >= 0; + if (r == -ENOENT) { + log_error_errno(r, "Shell '%s' does not exist, try again.", path); + return false; + } + if (ERRNO_IS_NEG_PRIVILEGE(r)) { + log_error_errno(r, "File '%s' is not executable, try again.", path); + return false; + } + if (r < 0) + return log_error_errno(r, "Failed to check if shell '%s' exists and is executable: %m", path); + + return true; +} + +static int prompt_shell(const char *username, char **ret_shell) { assert(username); assert(ret_shell); @@ -2798,38 +2824,45 @@ static int prompt_shell(const char *username, char **ret_shell) { return 0; } - _cleanup_free_ char *shell = NULL; - for (;;) { - shell = mfree(shell); + putchar('\n'); - r = ask_string(&shell, - "%s Please enter the shell to use for user %s (empty for default): ", - glyph(GLYPH_TRIANGULAR_BULLET), username); - if (r < 0) - return log_error_errno(r, "Failed to query user for username: %m"); - - if (isempty(shell)) { - log_info("No data entered, leaving at default."); - break; - } + _cleanup_free_ char *q = strjoin("Please enter the shell to use for user ", username); + if (!q) + return log_oom(); - if (!valid_shell(shell)) { - log_notice("Specified shell is not a valid UNIX shell path, try again: %s", shell); - continue; - } + return prompt_loop( + q, + GLYPH_SHELL, + /* menu= */ NULL, + /* accepted= */ NULL, + /* ellipsize_percentage= */ 0, + /* n_columns= */ 3, + /* column_width= */ 20, + shell_is_ok, + /* refresh= */ NULL, + /* userdata= */ NULL, + PROMPT_MAY_SKIP|PROMPT_SILENT_VALIDATE, + ret_shell); +} - r = RET_NERRNO(access(shell, X_OK)); - if (r >= 0) - break; +static int username_is_ok(const char *name, void *userdata) { + int r; - if (r != -ENOENT) - return log_error_errno(r, "Failed to check if shell %s exists: %m", shell); + assert(name); - log_notice("Specified shell '%s' is not installed, try another one.", shell); + if (!valid_user_group_name(name, /* flags= */ 0)) { + log_notice("Specified user name is not a valid UNIX user name, try again: %s", name); + return false; } - *ret_shell = TAKE_PTR(shell); - return 0; + r = userdb_by_name(name, /* match= */ NULL, USERDB_SUPPRESS_SHADOW, /* ret= */ NULL); + if (r == -ESRCH) + return true; + if (r < 0) + return log_error_errno(r, "Failed to check if specified user '%s' already exists: %m", name); + + log_notice("Specified user '%s' exists already, try again.", name); + return false; } static int create_interactively(void) { @@ -2862,33 +2895,22 @@ static int create_interactively(void) { return 0; } - for (;;) { - username = mfree(username); - - r = ask_string(&username, - "%s Please enter user name to create (empty to skip): ", - glyph(GLYPH_TRIANGULAR_BULLET)); - if (r < 0) - return log_error_errno(r, "Failed to query user for username: %m"); - - if (isempty(username)) { - log_info("No data entered, skipping."); - return 0; - } - - if (!valid_user_group_name(username, /* flags= */ 0)) { - log_notice("Specified user name is not a valid UNIX user name, try again: %s", username); - continue; - } - - r = userdb_by_name(username, /* match= */ NULL, USERDB_SUPPRESS_SHADOW, /* ret= */ NULL); - if (r == -ESRCH) - break; - if (r < 0) - return log_error_errno(r, "Failed to check if specified user '%s' already exists: %m", username); - - log_notice("Specified user '%s' exists already, try again.", username); - } + r = prompt_loop("Please enter user name to create", + GLYPH_IDCARD, + /* menu= */ NULL, + /* accepted= */ NULL, + /* ellipsize_percentage= */ 60, + /* n_columns= */ 3, + /* column_width= */ 20, + username_is_ok, + /* refresh= */ NULL, + /* userdata= */ NULL, + PROMPT_MAY_SKIP|PROMPT_SILENT_VALIDATE, + &username); + if (r < 0) + return r; + if (isempty(username)) + return 0; r = sd_json_variant_set_field_string(&arg_identity_extra, "userName", username); if (r < 0) @@ -2932,7 +2954,14 @@ static int create_interactively(void) { return log_error_errno(r, "Failed to set shell field: %m"); } - return create_home_common(/* input= */ NULL, /* show_enforce_password_policy_hint= */ false); + putchar('\n'); + + r = create_home_common(/* input= */ NULL, /* show_enforce_password_policy_hint= */ false); + if (r < 0) + return r; + + log_info("Successfully created account '%s'.", username); + return 0; } static int add_signing_keys_from_credentials(void);