From 27fd7278a1fedd2a5ec71c0258de14a083904916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=90o=C3=A0n=20Tr=E1=BA=A7n=20C=C3=B4ng=20Danh?= Date: Tue, 5 Jan 2021 20:55:46 +0700 Subject: [PATCH] getopt: explicitly ask for POSIX mode on POSIXLY_CORRECT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GNU libc's getopt_long(3) have the tradition of not shuffling arguments to find options when either POSIXLY_CORRECT is defined in environment variables or '+' prepended in short options. Hence, the current code base is fine as is fine as is for util-linux built with GNU libc. However, musl libc only honour POSIX convention when short options prepended with '+'. musl libc doesn't care about POSIXLY_CORRECT. Thus, the behaviour of util-linux's getopt(1) that linked with musl-libc doesn't match with its own documentation. Let's make sure a '+' is always prepended to short options if POSIXLY_CORRECT is defined. Signed-off-by: Đoàn Trần Công Danh --- misc-utils/Makemodule.am | 1 + misc-utils/getopt.1.in | 6 +++++- misc-utils/getopt.c | 18 +++++++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/misc-utils/Makemodule.am b/misc-utils/Makemodule.am index a01ca36bc..59dea5875 100644 --- a/misc-utils/Makemodule.am +++ b/misc-utils/Makemodule.am @@ -205,6 +205,7 @@ usrbin_exec_PROGRAMS += getopt dist_man_MANS += misc-utils/getopt.1 PATHFILES += misc-utils/getopt.1 getopt_SOURCES = misc-utils/getopt.c +getopt_LDADD = $(LDADD) libcommon.la getoptexampledir = $(docdir) dist_getoptexample_DATA = \ misc-utils/getopt-example.bash \ diff --git a/misc-utils/getopt.1.in b/misc-utils/getopt.1.in index b18d02820..a37cac03c 100644 --- a/misc-utils/getopt.1.in +++ b/misc-utils/getopt.1.in @@ -382,7 +382,11 @@ will be parsed. It will still do parameter shuffling (i.e., all non\-option parameters are output at the end), unless the environment variable .B POSIXLY_CORRECT -is set. +is set, in which case, +.B getopt +will prepend a +.RB ' + ' +before short options automatically. .PP The environment variable .B GETOPT_COMPATIBLE diff --git a/misc-utils/getopt.c b/misc-utils/getopt.c index 01a2df6dd..3fc38c97d 100644 --- a/misc-utils/getopt.c +++ b/misc-utils/getopt.c @@ -69,6 +69,7 @@ #include "closestream.h" #include "nls.h" +#include "strutils.h" #include "xalloc.h" /* NON_OPT is the code that is returned getopt(3) when a non-option is @@ -275,6 +276,18 @@ static void add_longopt(struct getopt_control *ctl, const char *name, int has_ar } +static void add_short_options(struct getopt_control *ctl, char *options) +{ + free(ctl->optstr); + if (*options != '+' && getenv("POSIXLY_CORRECT")) + ctl->optstr = strappend("+", options); + else + ctl->optstr = xstrdup(options); + if (!ctl->optstr) + err_oom(); +} + + /* * Register several long options. options is a string of long options, * separated by commas or whitespace. This nukes options! @@ -414,8 +427,7 @@ int main(int argc, char *argv[]) getopt_long_fp = getopt_long_only; break; case 'o': - free(ctl.optstr); - ctl.optstr = xstrdup(optarg); + add_short_options(&ctl, optarg); break; case 'l': add_long_options(&ctl, optarg); @@ -455,7 +467,7 @@ int main(int argc, char *argv[]) if (optind >= argc) parse_error(_("missing optstring argument")); else { - ctl.optstr = xstrdup(argv[optind]); + add_short_options(&ctl, argv[optind]); optind++; } }