From patchwork Fri Jan 18 10:11:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Richard W.M. Jones" X-Patchwork-Id: 10769657 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E8C886C2 for ; Fri, 18 Jan 2019 10:15:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D55DE29B65 for ; Fri, 18 Jan 2019 10:15:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C9BD72A21A; Fri, 18 Jan 2019 10:15:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4ACCF29B65 for ; Fri, 18 Jan 2019 10:15:17 +0000 (UTC) Received: from localhost ([127.0.0.1]:35534 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gkRBE-0006Em-7S for patchwork-qemu-devel@patchwork.kernel.org; Fri, 18 Jan 2019 05:15:16 -0500 Received: from eggs.gnu.org ([209.51.188.92]:45796) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gkR7i-0003Nz-VB for qemu-devel@nongnu.org; Fri, 18 Jan 2019 05:11:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gkR7g-0000e8-Tc for qemu-devel@nongnu.org; Fri, 18 Jan 2019 05:11:38 -0500 Received: from mx1.redhat.com ([209.132.183.28]:53836) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gkR7Z-0000Je-4X; Fri, 18 Jan 2019 05:11:30 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 230408AE45; Fri, 18 Jan 2019 10:11:20 +0000 (UTC) Received: from foo.home.annexia.org (ovpn-116-61.ams2.redhat.com [10.36.116.61]) by smtp.corp.redhat.com (Postfix) with ESMTP id B392F600C2; Fri, 18 Jan 2019 10:11:18 +0000 (UTC) From: "Richard W.M. Jones" To: kwolf@redhat.com Date: Fri, 18 Jan 2019 10:11:14 +0000 Message-Id: <20190118101114.11759-2-rjones@redhat.com> In-Reply-To: <20190118101114.11759-1-rjones@redhat.com> References: <20190118101114.11759-1-rjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Fri, 18 Jan 2019 10:11:20 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v4] qemu-io: Add generic function for reinitializing optind. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-devel@nongnu.org, qemu-block@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP On FreeBSD 11.2: $ nbdkit memory size=1M --run './qemu-io -f raw -c "aio_write 0 512" $nbd' Parsing error: non-numeric argument, or extraneous/unrecognized suffix -- aio_write After main option parsing, we reinitialize optind so we can parse each command. However reinitializing optind to 0 does not work on FreeBSD. What happens when you do this is optind remains 0 after the option parsing loop, and the result is we try to parse argv[optind] == argv[0] == "aio_write" as if it was the first parameter. The FreeBSD manual page says: In order to use getopt() to evaluate multiple sets of arguments, or to evaluate a single set of arguments multiple times, the variable optreset must be set to 1 before the second and each additional set of calls to getopt(), and the variable optind must be reinitialized. (From the rest of the man page it is clear that optind must be reinitialized to 1). The glibc man page says: A program that scans multiple argument vectors, or rescans the same vector more than once, and wants to make use of GNU extensions such as '+' and '-' at the start of optstring, or changes the value of POSIXLY_CORRECT between scans, must reinitialize getopt() by resetting optind to 0, rather than the traditional value of 1. (Resetting to 0 forces the invocation of an internal initialization routine that rechecks POSIXLY_CORRECT and checks for GNU extensions in optstring.) This commit introduces an OS-portability function called qemu_reset_optind which provides a way of resetting optind that works on FreeBSD and platforms that use optreset, while keeping it the same as now on other platforms. Note that the qemu codebase sets optind in many other places, but in those other places it's setting a local variable and not using getopt. This change is only needed in places where we are using getopt and the associated global variable optind. Signed-off-by: Richard W.M. Jones Reviewed-by: Daniel P. Berrangé Reviewed-by: Eric Blake --- configure | 14 ++++++++++++++ include/qemu/osdep.h | 16 ++++++++++++++++ qemu-img.c | 2 +- qemu-io-cmds.c | 2 +- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 3eee3fcf70..3d46df1517 100755 --- a/configure +++ b/configure @@ -4215,6 +4215,17 @@ if compile_prog "" "" ; then signalfd=yes fi +# check if optreset global is declared by +optreset="no" +cat > $TMPC << EOF +#include +int main(void) { return optreset; } +EOF + +if compile_prog "" "" ; then + optreset=yes +fi + # check if eventfd is supported eventfd=no cat > $TMPC << EOF @@ -6577,6 +6588,9 @@ fi if test "$signalfd" = "yes" ; then echo "CONFIG_SIGNALFD=y" >> $config_host_mak fi +if test "$optreset" = "yes" ; then + echo "HAVE_OPTRESET=y" >> $config_host_mak +fi if test "$tcg" = "yes"; then echo "CONFIG_TCG=y" >> $config_host_mak if test "$tcg_interpreter" = "yes" ; then diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index 80df7253db..840af09cb0 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -109,6 +109,7 @@ extern int daemon(int, int); #include #include #include +#include #include #include #include @@ -604,4 +605,19 @@ extern int qemu_icache_linesize_log; extern int qemu_dcache_linesize; extern int qemu_dcache_linesize_log; +/* + * After using getopt or getopt_long, if you need to parse another set + * of options, then you must reset optind. Unfortunately the way to + * do this varies between implementations of getopt. + */ +static inline void qemu_reset_optind(void) +{ +#ifdef HAVE_OPTRESET + optind = 1; + optreset = 1; +#else + optind = 0; +#endif +} + #endif diff --git a/qemu-img.c b/qemu-img.c index ad04f59565..25288c4d18 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4962,7 +4962,7 @@ int main(int argc, char **argv) return 0; } argv += optind; - optind = 0; + qemu_reset_optind(); if (!trace_init_backends()) { exit(1); diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 2c39124036..ee8f56e46a 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -114,7 +114,7 @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc, } } - optind = 0; + qemu_reset_optind(); return ct->cfunc(blk, argc, argv); }