From patchwork Wed Oct 5 09:33:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Denis V. Lunev" X-Patchwork-Id: 9362687 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id D0104600C8 for ; Wed, 5 Oct 2016 09:36:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BFBE228384 for ; Wed, 5 Oct 2016 09:36:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B49EF2867A; Wed, 5 Oct 2016 09:36:09 +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=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C6C3128384 for ; Wed, 5 Oct 2016 09:36:06 +0000 (UTC) Received: from localhost ([::1]:47449 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bricP-0004ks-V5 for patchwork-qemu-devel@patchwork.kernel.org; Wed, 05 Oct 2016 05:36:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42654) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1briZn-00033Q-S0 for qemu-devel@nongnu.org; Wed, 05 Oct 2016 05:33:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1briZj-0006W7-JQ for qemu-devel@nongnu.org; Wed, 05 Oct 2016 05:33:23 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:39231 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1briZj-0006V4-2a for qemu-devel@nongnu.org; Wed, 05 Oct 2016 05:33:19 -0400 Received: from iris.sw.ru ([10.30.2.139]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id u959X81T022826; Wed, 5 Oct 2016 12:33:10 +0300 (MSK) From: "Denis V. Lunev" To: qemu-block@nongnu.org, qemu-devel@nongnu.org Date: Wed, 5 Oct 2016 12:33:07 +0300 Message-Id: <1475659988-20500-2-git-send-email-den@openvz.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1475659988-20500-1-git-send-email-den@openvz.org> References: <1475659988-20500-1-git-send-email-den@openvz.org> X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x X-Received-From: 195.214.232.25 Subject: [Qemu-devel] [PATCH 1/2] nbd: change option parsing scheme 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: Kevin Wolf , den@openvz.org, Denis Plotnikov , Max Reitz , Paolo Bonzini Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Denis Plotnikov This is a preparatory commit to make code more generic. We are going to add more options in the next patch. Signed-off-by: Denis Plotnikov Signed-off-by: Denis V. Lunev CC: Paolo Bonzini CC: Kevin Wolf CC: Max Reitz --- block/nbd.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 124 insertions(+), 19 deletions(-) diff --git a/block/nbd.c b/block/nbd.c index 6bc06d6..3b133ed 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -38,7 +38,9 @@ #include "qapi/qmp/qstring.h" #include "qemu/cutils.h" -#define EN_OPTSTR ":exportname=" +#define EN_OPTSTR "exportname" + +#define PATH_PARAM (1u << 0) typedef struct BDRVNBDState { NbdClientSession client; @@ -47,6 +49,46 @@ typedef struct BDRVNBDState { char *path, *host, *port, *export, *tlscredsid; } BDRVNBDState; +/* + * helpers for dealing with option parsing + * to ease futher params adding and managing + */ + +/* + * @param_flags - bit flags defining a set of param names to be parsed + */ +static bool parse_query_params(QueryParams *qp, QDict *options, + unsigned int param_flags) +{ + int i; + for (i = 0; i < qp->n; i++) { + QueryParam *param = &qp->p[i]; + + if ((PATH_PARAM & param_flags) && + strcmp(param->name, "socket") == 0) { + qdict_put(options, "path", qstring_from_str(param->value)); + continue; + } + + } + return true; +} + +static bool find_prohibited_params(QueryParams *qp, unsigned int param_flags) +{ + int i; + for (i = 0; i < qp->n; i++) { + QueryParam *param = &qp->p[i]; + + if ((PATH_PARAM & param_flags) && + strcmp(param->name, "socket") == 0) { + return true; + } + } + return false; +} + + static int nbd_parse_uri(const char *filename, QDict *options) { URI *uri; @@ -79,18 +121,18 @@ static int nbd_parse_uri(const char *filename, QDict *options) } qp = query_params_parse(uri->query); - if (qp->n > 1 || (is_unix && !qp->n) || (!is_unix && qp->n)) { - ret = -EINVAL; - goto out; - } if (is_unix) { /* nbd+unix:///export?socket=path */ - if (uri->server || uri->port || strcmp(qp->p[0].name, "socket")) { + if (uri->server || uri->port) { + ret = -EINVAL; + goto out; + } + + if (!parse_query_params(qp, options, PATH_PARAM)) { ret = -EINVAL; goto out; } - qdict_put(options, "path", qstring_from_str(qp->p[0].value)); } else { QString *host; /* nbd[+tcp]://host[:port]/export */ @@ -113,6 +155,11 @@ static int nbd_parse_uri(const char *filename, QDict *options) qdict_put(options, "port", qstring_from_str(port_str)); g_free(port_str); } + + if (find_prohibited_params(qp, PATH_PARAM)) { + ret = -EINVAL; + goto out; + } } out: @@ -127,7 +174,7 @@ static void nbd_parse_filename(const char *filename, QDict *options, Error **errp) { char *file; - char *export_name; + char *opt_str; const char *host_spec; const char *unixpath; @@ -150,17 +197,6 @@ static void nbd_parse_filename(const char *filename, QDict *options, file = g_strdup(filename); - export_name = strstr(file, EN_OPTSTR); - if (export_name) { - if (export_name[strlen(EN_OPTSTR)] == 0) { - goto out; - } - export_name[0] = 0; /* truncate 'file' */ - export_name += strlen(EN_OPTSTR); - - qdict_put(options, "export", qstring_from_str(export_name)); - } - /* extract the host_spec - fail if it's not nbd:... */ if (!strstart(file, "nbd:", &host_spec)) { error_setg(errp, "File name string for NBD must start with 'nbd:'"); @@ -173,8 +209,40 @@ static void nbd_parse_filename(const char *filename, QDict *options, /* are we a UNIX or TCP socket? */ if (strstart(host_spec, "unix:", &unixpath)) { + opt_str = (char *) unixpath; + + /* do we have any options? */ + /* unixpath could be unix: or unix:something:options */ + opt_str = strchr(opt_str, ':'); + + /* if we have any options then "divide" */ + /* the path and the options by replacing the last colon with "\0" */ + if (opt_str != NULL) { + /* truncate 'unixpath' replacing the last ":" */ + char *colon_pos = opt_str; + colon_pos[0] = '\0'; + opt_str++; + } qdict_put(options, "path", qstring_from_str(unixpath)); } else { + /* host_spec could be ip:port or ip:port:options */ + int i; + opt_str = (char *)host_spec; + for (i = 0; i < 2; i++) { + opt_str = strchr(opt_str, ':'); + if (opt_str == NULL) { + break; + } + opt_str++; + } + + /* the same idea with dividing as above */ + if (opt_str != NULL) { + /* truncate 'host_name' replacing the last ":" */ + char *second_colon_pos = opt_str - 1; + second_colon_pos[0] = '\0'; + } + InetSocketAddress *addr = NULL; addr = inet_parse(host_spec, errp); @@ -187,6 +255,43 @@ static void nbd_parse_filename(const char *filename, QDict *options, qapi_free_InetSocketAddress(addr); } + /* opt_str == NULL means no options given */ + if (opt_str != NULL) { + static QemuOptsList file_opts = { + .name = "file_opts", + .head = QTAILQ_HEAD_INITIALIZER(file_opts.head), + .desc = { + { + .name = EN_OPTSTR, + .type = QEMU_OPT_STRING, + .help = "Name of the NBD export to open", + }, + }, + }; + + QemuOpts *opts = qemu_opts_create(&file_opts, NULL, 0, errp); + if (opts == NULL) { + error_setg(errp, "Can't parse file options"); + goto out; + } + + Error *local_err = NULL; + qemu_opts_do_parse(opts, opt_str, NULL, &local_err); + if (local_err) { + error_setg(errp, "Can't parse file options"); + qemu_opts_del(opts); + goto out; + } + + const char *value; + value = qemu_opt_get(opts, EN_OPTSTR); + if (value) { + qdict_put(options, "export", qstring_from_str(value)); + } + + qemu_opts_del(opts); + } + out: g_free(file); }