From d269a99bcceaaa866a0406d26fe992db1771e4ed Mon Sep 17 00:00:00 2001 From: 0xfadead Date: Sun, 15 Sep 2024 16:30:16 +0200 Subject: [PATCH 01/12] Add basic `--retry-input', without any function --- src/pacman/conf.h | 3 ++- src/pacman/pacman.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 5bffd187..d20eac47 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -214,7 +214,8 @@ enum { OP_REFRESH, OP_ASSUMEINSTALLED, OP_DISABLEDLTIMEOUT, - OP_DISABLESANDBOX + OP_DISABLESANDBOX, + OP_RETRYINPUT }; /* clean method */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 8f5fb6de..4e8d9dd1 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -228,6 +228,7 @@ static void usage(int op, const char * const myname) " use relaxed timeouts for download\n")); addlist(_(" --disable-sandbox\n" " disable the sandbox used for the downloader process\n")); + addlist(_(" --retry-input repeat prompts until a valid answer is supplied\n")); } list = alpm_list_msort(list, alpm_list_count(list), options_cmp); for(i = list; i; i = alpm_list_next(i)) { @@ -982,6 +983,7 @@ static int parseargs(int argc, char *argv[]) {"color", required_argument, 0, OP_COLOR}, {"disable-download-timeout", no_argument, 0, OP_DISABLEDLTIMEOUT}, {"disable-sandbox", no_argument, 0, OP_DISABLESANDBOX}, + {"retry-input", no_argument, 0, OP_RETRYINPUT}, {0, 0, 0, 0} }; From 9d72c82ec43dd6362d49e077be5290c4562b7b6f Mon Sep 17 00:00:00 2001 From: 0xfadead Date: Sun, 15 Sep 2024 16:32:49 +0200 Subject: [PATCH 02/12] Add config option for `--retry-input' --- src/pacman/conf.h | 1 + src/pacman/pacman.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/pacman/conf.h b/src/pacman/conf.h index d20eac47..4063a314 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -59,6 +59,7 @@ typedef struct __config_t { unsigned short color; unsigned short disable_dl_timeout; unsigned short disable_sandbox; + unsigned short retry_input; char *print_format; /* unfortunately, we have to keep track of paths both here and in the library * because they can come from both the command line or config file, and we diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 4e8d9dd1..3387ea21 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -500,6 +500,9 @@ static int parsearg_global(int opt) case 'v': (config->verbose)++; break; + case OP_RETRYINPUT: + config->retry_input = 1; + break; default: return 1; } From aeeaa3524c7ba990997dea939c62bb93616127d6 Mon Sep 17 00:00:00 2001 From: 0xfadead Date: Sun, 15 Sep 2024 17:08:26 +0200 Subject: [PATCH 03/12] Add `PACMAN_MIN()' and `PACMAN_MAX()' --- src/pacman/util.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pacman/util.h b/src/pacman/util.h index 9112633f..8db1d8ab 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -41,6 +41,11 @@ #define _n(str1, str2, ct) (char *)(ct == 1 ? str1 : str2) #endif +/* Macro to determine minimal value */ +#define PACMAN_MIN(a, b) ((a) > (b) ? (b) : (a)) +/* Macro to determine maximum value */ +#define PACMAN_MAX(a, b) ((a) > (b) ? (a) : (b)) + typedef struct _pm_target_t { alpm_pkg_t *remove; alpm_pkg_t *install; From b3521680fdd58486e82d40b3c6f7c3e90be99907 Mon Sep 17 00:00:00 2001 From: 0xfadead Date: Sun, 15 Sep 2024 19:54:41 +0200 Subject: [PATCH 04/12] Added code for `--retry-input' in question() --- src/pacman/util.c | 121 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 29 deletions(-) diff --git a/src/pacman/util.c b/src/pacman/util.c index 0736b8d6..5d4dbfc7 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1710,6 +1710,14 @@ static int question(short preset, const char *format, va_list args) FILE *stream; int fd_in = fileno(stdin); + va_list args_copy; + int format_len; + /* No need to initialize: + * the other calls also print a termination character */ + char prompt_cache_stack[256]; + char *prompt_cache = prompt_cache_stack; + size_t prompt_cache_size = sizeof(prompt_cache_stack); + if(config->noconfirm) { stream = stdout; } else { @@ -1717,47 +1725,102 @@ static int question(short preset, const char *format, va_list args) stream = stderr; } - /* ensure all text makes it to the screen before we prompt the user */ - fflush(stdout); - fflush(stderr); + /* Cache prompt, because we can't call v*printf() multiple times + * on the same arguments. */ + /* Copy args so we can retry when the buffer is too small */ + va_copy(args_copy, args); - fputs(config->colstr.colon, stream); - vfprintf(stream, format, args); + /* Don't ask me why v*printf() returns an Integer instead of a long */ + format_len = vsnprintf( + prompt_cache, + prompt_cache_size, + format, args); - if(preset) { - fprintf(stream, " %s ", _("[Y/n]")); - } else { - fprintf(stream, " %s ", _("[y/N]")); + /* Something has gone wrong */ + if (format_len < 1) { + pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: %s\n"), strerror(errno)); + return 0; } - fputs(config->colstr.nocolor, stream); - fflush(stream); + /* Buffer is too small */ + if ((size_t)format_len + 1 > prompt_cache_size) { + prompt_cache = malloc(format_len + 1); + prompt_cache_size = format_len + 1; + if (prompt_cache == 0) { + pm_printf(ALPM_LOG_ERROR, _("malloc failure: could not allocate %i bytes\n"), format_len + 1); - if(config->noconfirm) { - fprintf(stream, "\n"); - return preset; - } - - flush_term_input(fd_in); - - if(safe_fgets_stdin(response, sizeof(response))) { - size_t len = strtrim(response); - if(len == 0) { - return preset; + va_end(args_copy); + return 0; } - /* if stdin is piped, response does not get printed out, and as a result - * a \n is missing, resulting in broken output */ - if(!isatty(fd_in)) { - fprintf(stream, "%s\n", response); + format_len = vsnprintf(prompt_cache, prompt_cache_size, format, args_copy); + /* Something has gone wrong */ + if (format_len < 1) { + pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: %s\n"), strerror(errno)); + + va_end(args_copy); + return 0; } - if(mbscasecmp(response, _("Y")) == 0 || mbscasecmp(response, _("YES")) == 0) { - return 1; - } else if(mbscasecmp(response, _("N")) == 0 || mbscasecmp(response, _("NO")) == 0) { + /* Just in case */ + if ((size_t)format + 1 != prompt_cache_size) { + pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: Required size: %zu -> %i bytes\n"), prompt_cache_size, format_len + 1); + + va_end(args_copy); return 0; } } + + /* We can free the args-copy now */ + va_end(args_copy); + + /* Prompt the user at least once before exiting */ + do { + /* ensure all text makes it to the screen before we prompt the user */ + fflush(stdout); + fflush(stderr); + + fputs(config->colstr.colon, stream); + fputs(prompt_cache, stream); + + if(preset) { + fprintf(stream, " %s ", _("[Y/n]")); + } else { + fprintf(stream, " %s ", _("[y/N]")); + } + + fputs(config->colstr.nocolor, stream); + fflush(stream); + + if(config->noconfirm) { + fprintf(stream, "\n"); + return preset; + } + + flush_term_input(fd_in); + + if(safe_fgets_stdin(response, sizeof(response))) { + size_t len = strtrim(response); + if(len == 0) { + return preset; + } + + /* if stdin is piped, response does not get printed out, and as a result + * a \n is missing, resulting in broken output */ + if(!isatty(fd_in)) { + fprintf(stream, "%s\n", response); + } + + if(mbscasecmp(response, _("Y")) == 0 || mbscasecmp(response, _("YES")) == 0) { + return 1; + } else if(mbscasecmp(response, _("N")) == 0 || mbscasecmp(response, _("NO")) == 0) { + return 0; + } else + /* Emulate same behaviour as multiselect_question() and select_question() */ + fprintf(stream, _("invalid input: prompt requires `%s' or `%s'\n\n"), _("Y"), _("N")); + } + } while (config->retry_input); + return 0; } From a3783619f2d60dc886e717762888aafc19d4bd0f Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Sun, 15 Sep 2024 21:39:58 +0200 Subject: [PATCH 05/12] Added new error message's and help-text's translation for en_GB --- src/pacman/po/en_GB.po | 14 ++++++++++++++ src/pacman/util.c | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/pacman/po/en_GB.po b/src/pacman/po/en_GB.po index 11664de1..1fa50396 100644 --- a/src/pacman/po/en_GB.po +++ b/src/pacman/po/en_GB.po @@ -1232,6 +1232,11 @@ msgstr "" " --disable-sandbox\n" " disable the sandbox used for the downloader process\n" +#: src/pacman/pacman.c:231 +#, c-format +msgid " --retry-input repeat prompts until a valid answer is supplied\n" +msgstr " --retry-input repeat prompts until a valid answer is supplied\n" + #: src/pacman/pacman.c:249 #, c-format msgid "" @@ -1777,6 +1782,10 @@ msgstr "[Y/n]" msgid "[y/N]" msgstr "[y/N]" +#: src/pacman/util.c:1741 src/pacman/util.c:1759 +msgid "vsnprintf failure: Failed to cache prompt: %s\n" +msgstr "vsnprintf failure: Failed to cache prompt: %s\n" + #: src/pacman/util.c:1751 #, c-format msgid "Y" @@ -1797,6 +1806,11 @@ msgstr "N" msgid "NO" msgstr "NO" +#: src/pacman/util.c:1767 +#, c-format +msgid "vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n" +msgstr "vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n" + #: src/pacman/util.c:1820 #, c-format msgid "failed to allocate string\n" diff --git a/src/pacman/util.c b/src/pacman/util.c index 5d4dbfc7..44ffc609 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1764,7 +1764,7 @@ static int question(short preset, const char *format, va_list args) /* Just in case */ if ((size_t)format + 1 != prompt_cache_size) { - pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: Required size: %zu -> %i bytes\n"), prompt_cache_size, format_len + 1); + pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n"), prompt_cache_size, format_len + 1); va_end(args_copy); return 0; From 4def69cd149e2554790b9b413b8a31c4c193e5cb Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Sun, 15 Sep 2024 22:54:32 +0200 Subject: [PATCH 06/12] Fixed potential memory-leak in question() --- src/pacman/util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pacman/util.c b/src/pacman/util.c index 44ffc609..38f8fc5f 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1739,6 +1739,8 @@ static int question(short preset, const char *format, va_list args) /* Something has gone wrong */ if (format_len < 1) { pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: %s\n"), strerror(errno)); + + va_end(args_copy); return 0; } From fd04ffa25ccca456c92e567a4cf77d297e57d136 Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Sun, 15 Sep 2024 22:55:04 +0200 Subject: [PATCH 07/12] Added german translations for new question() error messages and help message --- src/pacman/po/de.po | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/pacman/po/de.po b/src/pacman/po/de.po index 1d5d9e12..b351843d 100644 --- a/src/pacman/po/de.po +++ b/src/pacman/po/de.po @@ -1317,6 +1317,13 @@ msgid "" " --disable-sandbox\n" " disable the sandbox used for the downloader process\n" msgstr "" +" --disable-sandbox\n" +" shaltet Sandbox für den Download-Prozess aus\n" + +#: src/pacman/pacman.c:231 +#, c-format +msgid " --retry-input repeat prompts until a valid answer is supplied\n" +msgstr " --retry-input wiederholt Frage, bis eine valide Antwort gegeben wird\n" #: src/pacman/pacman.c:249 #, c-format @@ -1866,6 +1873,11 @@ msgstr "[J/n]" msgid "[y/N]" msgstr "[j/N]" +#: src/pacman/util.c:1741 +#, c-format +msgid "vsnprintf failure: Failed to cache prompt: %s\n" +msgstr "vsnprintf-fehler: Kann prompt nicht cachen: %s\n" + #: src/pacman/util.c:1751 #, c-format msgid "Y" @@ -1886,6 +1898,11 @@ msgstr "N" msgid "NO" msgstr "NEIN" +#: src/pacman/util.c:1769 +#, c-format +msgid "vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n" +msgstr "vsnprintf-fehler: Kann prompt nicht cachen: Benötigte Größe hat sich geändert: %zu -> %i bytes\n" + #: src/pacman/util.c:1820 #, c-format msgid "failed to allocate string\n" From 6bd2c3378f4a41c7ac8b11f969f5e8421ff7b42f Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Sun, 15 Sep 2024 22:58:06 +0200 Subject: [PATCH 08/12] Replaced `prompt' with `Frage' in german translation for question() --- src/pacman/po/de.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pacman/po/de.po b/src/pacman/po/de.po index b351843d..fdef635a 100644 --- a/src/pacman/po/de.po +++ b/src/pacman/po/de.po @@ -1876,7 +1876,7 @@ msgstr "[j/N]" #: src/pacman/util.c:1741 #, c-format msgid "vsnprintf failure: Failed to cache prompt: %s\n" -msgstr "vsnprintf-fehler: Kann prompt nicht cachen: %s\n" +msgstr "vsnprintf-fehler: Kann Frage nicht cachen: %s\n" #: src/pacman/util.c:1751 #, c-format @@ -1901,7 +1901,7 @@ msgstr "NEIN" #: src/pacman/util.c:1769 #, c-format msgid "vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n" -msgstr "vsnprintf-fehler: Kann prompt nicht cachen: Benötigte Größe hat sich geändert: %zu -> %i bytes\n" +msgstr "vsnprintf-fehler: Kann Frage nicht cachen: Benötigte Größe hat sich geändert: %zu -> %i bytes\n" #: src/pacman/util.c:1820 #, c-format From fed0c919ac40fb0e433a75b0a6fbb9844194529c Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Mon, 16 Sep 2024 00:41:57 +0200 Subject: [PATCH 09/12] Revert "Add `PACMAN_MIN()' and `PACMAN_MAX()'" This reverts commit aeeaa3524c7ba990997dea939c62bb93616127d6. --- src/pacman/util.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/pacman/util.h b/src/pacman/util.h index 8db1d8ab..9112633f 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -41,11 +41,6 @@ #define _n(str1, str2, ct) (char *)(ct == 1 ? str1 : str2) #endif -/* Macro to determine minimal value */ -#define PACMAN_MIN(a, b) ((a) > (b) ? (b) : (a)) -/* Macro to determine maximum value */ -#define PACMAN_MAX(a, b) ((a) > (b) ? (a) : (b)) - typedef struct _pm_target_t { alpm_pkg_t *remove; alpm_pkg_t *install; From 84311908bfd183d36efbc5197e2229966c6d3f75 Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Mon, 16 Sep 2024 00:46:52 +0200 Subject: [PATCH 10/12] Changed name from `--retry-input' to `--retry-prompt' --- src/pacman/pacman.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 3387ea21..ff5c36f2 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -228,7 +228,7 @@ static void usage(int op, const char * const myname) " use relaxed timeouts for download\n")); addlist(_(" --disable-sandbox\n" " disable the sandbox used for the downloader process\n")); - addlist(_(" --retry-input repeat prompts until a valid answer is supplied\n")); + addlist(_(" --retry-prompt repeat prompts until a valid answer is supplied\n")); } list = alpm_list_msort(list, alpm_list_count(list), options_cmp); for(i = list; i; i = alpm_list_next(i)) { @@ -986,7 +986,7 @@ static int parseargs(int argc, char *argv[]) {"color", required_argument, 0, OP_COLOR}, {"disable-download-timeout", no_argument, 0, OP_DISABLEDLTIMEOUT}, {"disable-sandbox", no_argument, 0, OP_DISABLESANDBOX}, - {"retry-input", no_argument, 0, OP_RETRYINPUT}, + {"retry-prompt", no_argument, 0, OP_RETRYINPUT}, {0, 0, 0, 0} }; From 6da7769dff649c507728896fa36f2cf2026d1a84 Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Mon, 16 Sep 2024 00:47:18 +0200 Subject: [PATCH 11/12] Changed name from `--retry-input' to `--retry-prompt' in translations --- src/pacman/po/de.po | 4 ++-- src/pacman/po/en_GB.po | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pacman/po/de.po b/src/pacman/po/de.po index fdef635a..146b0b54 100644 --- a/src/pacman/po/de.po +++ b/src/pacman/po/de.po @@ -1322,8 +1322,8 @@ msgstr "" #: src/pacman/pacman.c:231 #, c-format -msgid " --retry-input repeat prompts until a valid answer is supplied\n" -msgstr " --retry-input wiederholt Frage, bis eine valide Antwort gegeben wird\n" +msgid " --retry-prompt repeat prompts until a valid answer is supplied\n" +msgstr " --retry-prompt wiederholt Frage, bis eine valide Antwort gegeben wird\n" #: src/pacman/pacman.c:249 #, c-format diff --git a/src/pacman/po/en_GB.po b/src/pacman/po/en_GB.po index 1fa50396..0189ec22 100644 --- a/src/pacman/po/en_GB.po +++ b/src/pacman/po/en_GB.po @@ -1234,8 +1234,8 @@ msgstr "" #: src/pacman/pacman.c:231 #, c-format -msgid " --retry-input repeat prompts until a valid answer is supplied\n" -msgstr " --retry-input repeat prompts until a valid answer is supplied\n" +msgid " --retry-prompt repeat prompts until a valid answer is supplied\n" +msgstr " --retry-prompt repeat prompts until a valid answer is supplied\n" #: src/pacman/pacman.c:249 #, c-format From cf16079693254300a332ee8a8005074955ca5300 Mon Sep 17 00:00:00 2001 From: someordinaryidiot# Date: Mon, 16 Sep 2024 02:00:30 +0200 Subject: [PATCH 12/12] Changed layout of function `question()' and fixed the most obvious memory-leak in the history of the universe --- src/pacman/util.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/pacman/util.c b/src/pacman/util.c index 38f8fc5f..fc2ba590 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1706,6 +1706,7 @@ static int mbscasecmp(const char *s1, const char *s2) __attribute__((format(printf, 2, 0))) static int question(short preset, const char *format, va_list args) { + int return_code = 0; char response[32]; FILE *stream; int fd_in = fileno(stdin); @@ -1740,8 +1741,7 @@ static int question(short preset, const char *format, va_list args) if (format_len < 1) { pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: %s\n"), strerror(errno)); - va_end(args_copy); - return 0; + goto free_args_copy; } /* Buffer is too small */ @@ -1751,8 +1751,7 @@ static int question(short preset, const char *format, va_list args) if (prompt_cache == 0) { pm_printf(ALPM_LOG_ERROR, _("malloc failure: could not allocate %i bytes\n"), format_len + 1); - va_end(args_copy); - return 0; + goto free_args_copy; } format_len = vsnprintf(prompt_cache, prompt_cache_size, format, args_copy); @@ -1760,25 +1759,23 @@ static int question(short preset, const char *format, va_list args) if (format_len < 1) { pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: %s\n"), strerror(errno)); - va_end(args_copy); - return 0; + goto free_args_copy; } /* Just in case */ if ((size_t)format + 1 != prompt_cache_size) { pm_printf(ALPM_LOG_ERROR, _("vsnprintf failure: Failed to cache prompt: Required size changed: %zu -> %i bytes\n"), prompt_cache_size, format_len + 1); - va_end(args_copy); - return 0; + goto free_args_copy; } } - /* We can free the args-copy now */ + /* We can free the argument-copy now */ va_end(args_copy); /* Prompt the user at least once before exiting */ do { - /* ensure all text makes it to the screen before we prompt the user */ + /* Ensure all text makes it to the screen before we prompt the user */ fflush(stdout); fflush(stderr); @@ -1804,7 +1801,8 @@ static int question(short preset, const char *format, va_list args) if(safe_fgets_stdin(response, sizeof(response))) { size_t len = strtrim(response); if(len == 0) { - return preset; + return_code = preset; + goto opt_free_cache; } /* if stdin is piped, response does not get printed out, and as a result @@ -1814,16 +1812,24 @@ static int question(short preset, const char *format, va_list args) } if(mbscasecmp(response, _("Y")) == 0 || mbscasecmp(response, _("YES")) == 0) { - return 1; + return_code = 1; + goto opt_free_cache; } else if(mbscasecmp(response, _("N")) == 0 || mbscasecmp(response, _("NO")) == 0) { - return 0; + goto opt_free_cache; } else /* Emulate same behaviour as multiselect_question() and select_question() */ fprintf(stream, _("invalid input: prompt requires `%s' or `%s'\n\n"), _("Y"), _("N")); } } while (config->retry_input); - return 0; +opt_free_cache: + if (prompt_cache != prompt_cache_stack) + free(prompt_cache); + return return_code; + +free_args_copy: + va_end(args_copy); + return return_code; } int yesno(const char *format, ...)