diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-10-12 00:08:31 +0300 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-10-12 00:08:31 +0300 |
commit | f4fcd74a6e3d5cd2ec44cd6ce90be8a0ed108467 (patch) | |
tree | d79b1828fa7f42bda6f0c3e3d8ad5d73da2e3e0a /libbb/lineedit.c | |
parent | 6ba1f2d0bcdddb96c43ff9fec34758a4e2b4a467 (diff) |
shell: do not read user database for every prompt - only for those which need it
function old new delta
get_user_strings - 52 +52
get_homedir_or_NULL - 23 +23
parse_and_put_prompt 823 838 +15
null_str 1 - -1
complete_cmd_dir_file 814 812 -2
deinit_S 51 42 -9
read_line_input 3059 3015 -44
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 1/3 up/down: 90/-56) Total: 34 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r-- | libbb/lineedit.c | 73 |
1 files changed, 46 insertions, 27 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 9960448ec..e14c78707 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -135,10 +135,6 @@ enum { : 0x7ff0 }; -#if ENABLE_USERNAME_OR_HOMEDIR -static const char null_str[] ALIGN1 = ""; -#endif - /* We try to minimize both static and stack usage. */ struct lineedit_statics { line_input_t *state; @@ -161,12 +157,13 @@ struct lineedit_statics { #if ENABLE_USERNAME_OR_HOMEDIR char *user_buf; - char *home_pwd_buf; /* = (char*)null_str; */ + char *home_pwd_buf; + smallint got_user_strings; #endif #if ENABLE_FEATURE_TAB_COMPLETION - char **matches; unsigned num_matches; + char **matches; #endif #if ENABLE_FEATURE_EDITING_WINCH @@ -207,8 +204,9 @@ extern struct lineedit_statics *BB_GLOBAL_CONST lineedit_ptr_to_statics; #define prompt_last_line (S.prompt_last_line) #define user_buf (S.user_buf ) #define home_pwd_buf (S.home_pwd_buf ) -#define matches (S.matches ) +#define got_user_strings (S.got_user_strings) #define num_matches (S.num_matches ) +#define matches (S.matches ) #define delptr (S.delptr ) #define newdelflag (S.newdelflag ) #define delbuf (S.delbuf ) @@ -226,14 +224,47 @@ static void deinit_S(void) #endif #if ENABLE_USERNAME_OR_HOMEDIR free(user_buf); - if (home_pwd_buf != null_str) - free(home_pwd_buf); + free(home_pwd_buf); #endif free(lineedit_ptr_to_statics); } #define DEINIT_S() deinit_S() +#if ENABLE_USERNAME_OR_HOMEDIR +/* Call getpwuid() only if necessary. + * E.g. if PS1=':', no user database reading is needed to generate prompt. + * (Unfortunately, default PS1='\w \$' needs it, \w abbreviates homedir + * as ~/... - for that it needs to *know* the homedir...) + */ +static void get_user_strings(void) +{ + struct passwd *entry; + + got_user_strings = 1; + entry = getpwuid(geteuid()); + if (entry) { + user_buf = xstrdup(entry->pw_name); + home_pwd_buf = xstrdup(entry->pw_dir); + } +} + +static const char *get_username_str(void) +{ + if (!got_user_strings) + get_user_strings(); + return user_buf ? user_buf : ""; + /* btw, bash uses "I have no name!" string if uid has no entry */ +} + +static NOINLINE const char *get_homedir_or_NULL(void) +{ + if (!got_user_strings) + get_user_strings(); + return home_pwd_buf; +} +#endif + #if ENABLE_UNICODE_SUPPORT static size_t load_string(const char *src) { @@ -691,11 +722,11 @@ static char *username_path_completion(char *ud) { struct passwd *entry; char *tilde_name = ud; - char *home = NULL; + const char *home = NULL; ud++; /* skip ~ */ if (*ud == '/') { /* "~/..." */ - home = home_pwd_buf; + home = get_homedir_or_NULL(); } else { /* "~user/..." */ ud = strchr(ud, '/'); @@ -1971,7 +2002,7 @@ static void parse_and_put_prompt(const char *prmt_ptr) switch (c) { case 'u': - pbuf = user_buf ? user_buf : (char*)""; + pbuf = (char*)get_username_str(); break; case 'H': case 'h': @@ -1993,14 +2024,15 @@ static void parse_and_put_prompt(const char *prmt_ptr) case 'w': /* current dir */ case 'W': /* basename of cur dir */ if (!cwd_buf) { + const char *home; cwd_buf = xrealloc_getcwd_or_warn(NULL); if (!cwd_buf) cwd_buf = (char *)bb_msg_unknown; - else if (home_pwd_buf[0]) { + else if ((home = get_homedir_or_NULL()) != NULL && home[0]) { char *after_home_user; /* /home/user[/something] -> ~[/something] */ - after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf); + after_home_user = is_prefixed_with(cwd_buf, home); if (after_home_user && (*after_home_user == '/' || *after_home_user == '\0') ) { @@ -2399,7 +2431,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman //command_len = 0; - done by INIT_S() //cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ cmdedit_termw = 80; - IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) IF_FEATURE_EDITING_VI(delptr = delbuf;) n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 @@ -2459,18 +2490,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman tcsetattr_stdin_TCSANOW(&new_settings); -#if ENABLE_USERNAME_OR_HOMEDIR - { - struct passwd *entry; - - entry = getpwuid(geteuid()); - if (entry) { - user_buf = xstrdup(entry->pw_name); - home_pwd_buf = xstrdup(entry->pw_dir); - } - } -#endif - #if 0 for (i = 0; i <= state->max_history; i++) bb_error_msg("history[%d]:'%s'", i, state->history[i]); |