Implement getopt via getopt_long to support glibc-style non-options before options
Musl's getopt follows the POSIX standard and stops parsing options
when it finds the first non-option argument. Glibc by default will
continue parsing options, permuting all non-option arguments to the
end of argv. This behavior is visible to users of command line tools
that use getopt. To avoid breaking existing usages of command line
tools reimplement getopt via getopt_long, which is a glibc extension
and already includes the permuting logic. The original getopt is
renamed to __posix_getopt, replacing the existing __posix_getopt weak
symbol.
Test: debugfs_static foo -h prints help message
Test: POSIXLY_CORRECT=1 debugfs_static foo -h tries to open foo
Change-Id: I5890312a07659c3f0706a6ac8c4a49a43e9c84c8
diff --git a/src/misc/getopt.c b/src/misc/getopt.c
index c3f6699..f8df7ae 100644
--- a/src/misc/getopt.c
+++ b/src/misc/getopt.c
@@ -25,7 +25,7 @@
FUNLOCK(f);
}
-int getopt(int argc, char * const argv[], const char *optstring)
+int __posix_getopt(int argc, char * const argv[], const char *optstring)
{
int i;
wchar_t c, d;
@@ -101,5 +101,3 @@
}
return c;
}
-
-weak_alias(getopt, __posix_getopt);
diff --git a/src/misc/getopt_long.c b/src/misc/getopt_long.c
index 6949ab1..117d1a1 100644
--- a/src/misc/getopt_long.c
+++ b/src/misc/getopt_long.c
@@ -9,6 +9,8 @@
extern int __optpos, __optreset;
+int __posix_getopt(int argc, char * const argv[], const char *optstring);
+
static void permute(char *const *argv, int dest, int src)
{
char **av = (char **)argv;
@@ -134,7 +136,7 @@
return '?';
}
}
- return getopt(argc, argv, optstring);
+ return __posix_getopt(argc, argv, optstring);
}
int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
@@ -146,3 +148,20 @@
{
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
}
+
+/* ANDROID CHANGE: implement getopt via getopt_long to continue parsing options
+ * after the first non-option argument to match the user visible behavior of
+ * glibc.
+ */
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+ static int posixly_correct = -1;
+
+ if (posixly_correct == -1 || __optreset)
+ posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
+
+ if (posixly_correct)
+ return __posix_getopt(argc, argv, optstring);
+ else
+ return __getopt_long(argc, argv, optstring, NULL, NULL, 0);
+}