mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
fish: Split off URI handling (for -a argument) from general options parsing.
This is so we will be able to reuse the same code in the OCaml tools. This is just code motion.
This commit is contained in:
@@ -38,7 +38,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
virt_alignment_scan_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
|
||||
@@ -35,7 +35,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
virt_cat_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
|
||||
@@ -186,7 +186,11 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->a.filename = argv[optind];
|
||||
drv->a.filename = strdup (argv[optind]);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
} else { /* simulate -d option */
|
||||
|
||||
@@ -291,7 +291,11 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->a.filename = argv[optind];
|
||||
drv->a.filename = strdup (argv[optind]);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
} else { /* simulate -d option */
|
||||
|
||||
@@ -33,7 +33,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
virt_df_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
|
||||
@@ -220,7 +220,11 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->a.filename = argv[optind];
|
||||
drv->a.filename = strdup (argv[optind]);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
} else { /* simulate -d option */
|
||||
|
||||
@@ -31,7 +31,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
virt_edit_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
|
||||
@@ -223,7 +223,11 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->a.filename = argv[optind];
|
||||
drv->a.filename = strdup (argv[optind]);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
} else { /* simulate -d option */
|
||||
|
||||
@@ -70,7 +70,9 @@ SHARED_SOURCE_FILES = \
|
||||
options.h \
|
||||
options.c \
|
||||
progress.h \
|
||||
progress.c
|
||||
progress.c \
|
||||
uri.h \
|
||||
uri.c
|
||||
|
||||
guestfish_SOURCES = \
|
||||
$(generator_built) \
|
||||
|
||||
@@ -446,7 +446,11 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->a.filename = argv[optind];
|
||||
drv->a.filename = strdup (argv[optind]);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
} else { /* simulate -d option */
|
||||
|
||||
283
fish/options.c
283
fish/options.c
@@ -25,22 +25,15 @@
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include <libxml/uri.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "options.h"
|
||||
|
||||
static int is_uri (const char *arg);
|
||||
static void parse_uri (const char *arg, const char *format, struct drv *drv);
|
||||
static char *query_get (xmlURIPtr uri, const char *search_name);
|
||||
static char **make_server (xmlURIPtr uri, const char *socket);
|
||||
#include "uri.h"
|
||||
|
||||
/* Handle the '-a' option when passed on the command line. */
|
||||
void
|
||||
option_a (const char *arg, const char *format, struct drv **drvsp)
|
||||
{
|
||||
struct uri uri;
|
||||
struct drv *drv;
|
||||
|
||||
drv = calloc (1, sizeof (struct drv));
|
||||
@@ -49,268 +42,39 @@ option_a (const char *arg, const char *format, struct drv **drvsp)
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Does it look like a URI? */
|
||||
if (is_uri (arg))
|
||||
parse_uri (arg, format, drv);
|
||||
else {
|
||||
if (parse_uri (arg, &uri) == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
if (STREQ (uri.protocol, "file")) {
|
||||
/* Ordinary file. */
|
||||
if (access (arg, R_OK) != 0) {
|
||||
perror (arg);
|
||||
if (access (uri.path, R_OK) != 0) {
|
||||
perror (uri.path);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
drv->type = drv_a;
|
||||
drv->nr_drives = -1;
|
||||
drv->a.filename = (char *) arg;
|
||||
drv->a.filename = uri.path;
|
||||
drv->a.format = format;
|
||||
|
||||
free (uri.protocol);
|
||||
}
|
||||
else {
|
||||
/* Remote storage. */
|
||||
drv->type = drv_uri;
|
||||
drv->nr_drives = -1;
|
||||
drv->uri.path = uri.path;
|
||||
drv->uri.protocol = uri.protocol;
|
||||
drv->uri.server = uri.server;
|
||||
drv->uri.username = uri.username;
|
||||
drv->uri.format = format;
|
||||
drv->uri.orig_uri = arg;
|
||||
}
|
||||
|
||||
drv->next = *drvsp;
|
||||
*drvsp = drv;
|
||||
}
|
||||
|
||||
/* Does it "look like" a URI? A short lower-case ASCII string
|
||||
* followed by "://" will do. Note that we properly parse the URI
|
||||
* later on using libxml2.
|
||||
*/
|
||||
static int
|
||||
is_uri (const char *arg)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = strstr (arg, "://");
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
if (p - arg >= 8)
|
||||
return 0;
|
||||
|
||||
for (p--; p >= arg; p--) {
|
||||
if (!c_islower (*p))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_uri (const char *arg, const char *format, struct drv *drv)
|
||||
{
|
||||
CLEANUP_XMLFREEURI xmlURIPtr uri = NULL;
|
||||
CLEANUP_FREE char *socket = NULL;
|
||||
char *path;
|
||||
char *protocol;
|
||||
char **server;
|
||||
char *username;
|
||||
|
||||
uri = xmlParseURI (arg);
|
||||
if (!uri) {
|
||||
fprintf (stderr, _("%s: --add: could not parse URI '%s'\n"),
|
||||
program_name, arg);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Note we don't do much checking of the parsed URI, since the
|
||||
* underlying function 'guestfs_add_drive_opts' will check for us.
|
||||
* So just the basics here.
|
||||
*/
|
||||
if (uri->scheme == NULL) {
|
||||
/* Probably can never happen. */
|
||||
fprintf (stderr, _("%s: --add %s: scheme of URI is NULL\n"),
|
||||
program_name, arg);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
socket = query_get (uri, "socket");
|
||||
|
||||
if (uri->server && STRNEQ (uri->server, "") && socket) {
|
||||
fprintf (stderr, _("%s: --add %s: cannot both a server name and a socket query parameter\n"),
|
||||
program_name, arg);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Is this needed? XXX
|
||||
if (socket && socket[0] != '/') {
|
||||
fprintf (stderr, _("%s: --add %s: socket query parameter must be an absolute path\n"),
|
||||
program_name, arg);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
*/
|
||||
|
||||
protocol = strdup (uri->scheme);
|
||||
if (protocol == NULL) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
server = make_server (uri, socket);
|
||||
|
||||
if (uri->user && STRNEQ (uri->user, "")) {
|
||||
username = strdup (uri->user);
|
||||
if (!username) {
|
||||
perror ("username");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else username = NULL;
|
||||
|
||||
path = strdup (uri->path ? uri->path : "");
|
||||
if (!path) {
|
||||
perror ("path");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
drv->type = drv_uri;
|
||||
drv->nr_drives = -1;
|
||||
drv->uri.path = path;
|
||||
drv->uri.protocol = protocol;
|
||||
drv->uri.server = server;
|
||||
drv->uri.username = username;
|
||||
drv->uri.format = format;
|
||||
drv->uri.orig_uri = arg;
|
||||
}
|
||||
|
||||
/* Code inspired by libvirt src/util/viruri.c, written by danpb,
|
||||
* released under a compatible license.
|
||||
*/
|
||||
static char *
|
||||
query_get (xmlURIPtr uri, const char *search_name)
|
||||
{
|
||||
/* XXX libvirt uses deprecated uri->query field. Why? */
|
||||
const char *query = uri->query_raw;
|
||||
const char *end, *eq;
|
||||
|
||||
if (!query || STREQ (query, ""))
|
||||
return NULL;
|
||||
|
||||
while (*query) {
|
||||
CLEANUP_FREE char *name = NULL;
|
||||
char *value = NULL;
|
||||
|
||||
/* Find the next separator, or end of the string. */
|
||||
end = strchr (query, '&');
|
||||
if (!end)
|
||||
end = strchr(query, ';');
|
||||
if (!end)
|
||||
end = query + strlen (query);
|
||||
|
||||
/* Find the first '=' character between here and end. */
|
||||
eq = strchr(query, '=');
|
||||
if (eq && eq >= end) eq = NULL;
|
||||
|
||||
/* Empty section (eg. "&&"). */
|
||||
if (end == query)
|
||||
goto next;
|
||||
|
||||
/* If there is no '=' character, then we have just "name"
|
||||
* and consistent with CGI.pm we assume value is "".
|
||||
*/
|
||||
else if (!eq) {
|
||||
name = xmlURIUnescapeString (query, end - query, NULL);
|
||||
if (!name) goto no_memory;
|
||||
}
|
||||
/* Or if we have "name=" here (works around annoying
|
||||
* problem when calling xmlURIUnescapeString with len = 0).
|
||||
*/
|
||||
else if (eq+1 == end) {
|
||||
name = xmlURIUnescapeString (query, eq - query, NULL);
|
||||
if (!name) goto no_memory;
|
||||
}
|
||||
/* If the '=' character is at the beginning then we have
|
||||
* "=value" and consistent with CGI.pm we _ignore_ this.
|
||||
*/
|
||||
else if (query == eq)
|
||||
goto next;
|
||||
|
||||
/* Otherwise it's "name=value". */
|
||||
else {
|
||||
name = xmlURIUnescapeString (query, eq - query, NULL);
|
||||
if (!name)
|
||||
goto no_memory;
|
||||
value = xmlURIUnescapeString (eq+1, end - (eq+1), NULL);
|
||||
if (!value) {
|
||||
goto no_memory;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is it the name we're looking for? */
|
||||
if (STREQ (name, search_name)) {
|
||||
if (!value) {
|
||||
value = strdup ("");
|
||||
if (!value)
|
||||
goto no_memory;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
free (value);
|
||||
|
||||
next:
|
||||
query = end;
|
||||
if (*query)
|
||||
query++; /* skip '&' separator */
|
||||
}
|
||||
|
||||
/* search_name not found */
|
||||
return NULL;
|
||||
|
||||
no_memory:
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Construct either a tcp: server list of a unix: server list or
|
||||
* nothing at all from '-a' option URI.
|
||||
*/
|
||||
static char **
|
||||
make_server (xmlURIPtr uri, const char *socket)
|
||||
{
|
||||
char **ret;
|
||||
char *server;
|
||||
|
||||
/* If the server part of the URI is specified, then this is a TCP
|
||||
* connection.
|
||||
*/
|
||||
if (uri->server && STRNEQ (uri->server, "")) {
|
||||
if (uri->port == 0) {
|
||||
if (asprintf (&server, "tcp:%s", uri->server) == -1) {
|
||||
perror ("asprintf");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (asprintf (&server, "tcp:%s:%d", uri->server, uri->port) == -1) {
|
||||
perror ("asprintf");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Otherwise, ?socket query parameter means it's a Unix domain
|
||||
* socket connection.
|
||||
*/
|
||||
else if (socket != NULL) {
|
||||
if (asprintf (&server, "unix:%s", socket) == -1) {
|
||||
perror ("asprintf");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
/* Otherwise, no server parameter is needed. */
|
||||
else return NULL;
|
||||
|
||||
/* The .server parameter is in fact a list of strings, although
|
||||
* only a singleton is passed by us.
|
||||
*/
|
||||
ret = malloc (sizeof (char *) * 2);
|
||||
if (ret == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
ret[0] = server;
|
||||
ret[1] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char
|
||||
add_drives (struct drv *drv, char next_drive)
|
||||
{
|
||||
@@ -488,7 +252,8 @@ free_drives (struct drv *drv)
|
||||
|
||||
switch (drv->type) {
|
||||
case drv_a:
|
||||
/* a.filename and a.format are optargs, don't free them */
|
||||
free (drv->a.filename);
|
||||
/* a.format is an optarg, so don't free it */
|
||||
break;
|
||||
case drv_uri:
|
||||
free (drv->uri.path);
|
||||
|
||||
318
fish/uri.c
Normal file
318
fish/uri.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/* libguestfs - mini library for parsing -a URI parameters
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include <libxml/uri.h>
|
||||
|
||||
#include "c-ctype.h"
|
||||
|
||||
#include "guestfs.h"
|
||||
#include "guestfs-internal-frontend.h"
|
||||
#include "uri.h"
|
||||
|
||||
static int is_uri (const char *arg);
|
||||
static int parse (const char *arg, char **path_ret, char **protocol_ret, char ***server_ret, char **username_ret);
|
||||
static char *query_get (xmlURIPtr uri, const char *search_name);
|
||||
static int make_server (xmlURIPtr uri, const char *socket, char ***ret);
|
||||
|
||||
int
|
||||
parse_uri (const char *arg, struct uri *uri_ret)
|
||||
{
|
||||
char *path;
|
||||
char *protocol;
|
||||
char **server;
|
||||
char *username;
|
||||
|
||||
/* Does it look like a URI? */
|
||||
if (is_uri (arg)) {
|
||||
if (parse (arg, &path, &protocol, &server, &username) == -1)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
/* Ordinary file. */
|
||||
path = strdup (arg);
|
||||
if (!path) {
|
||||
perror ("strdup");
|
||||
return -1;
|
||||
}
|
||||
protocol = strdup ("file");
|
||||
if (!protocol) {
|
||||
perror ("strdup");
|
||||
free (path);
|
||||
return -1;
|
||||
}
|
||||
server = NULL;
|
||||
username = NULL;
|
||||
}
|
||||
|
||||
uri_ret->path = path;
|
||||
uri_ret->protocol = protocol;
|
||||
uri_ret->server = server;
|
||||
uri_ret->username = username;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Does it "look like" a URI? A short lower-case ASCII string
|
||||
* followed by "://" will do. Note that we properly parse the URI
|
||||
* later on using libxml2.
|
||||
*/
|
||||
static int
|
||||
is_uri (const char *arg)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = strstr (arg, "://");
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
if (p - arg >= 8)
|
||||
return 0;
|
||||
|
||||
for (p--; p >= arg; p--) {
|
||||
if (!c_islower (*p))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
parse (const char *arg, char **path_ret, char **protocol_ret,
|
||||
char ***server_ret, char **username_ret)
|
||||
{
|
||||
CLEANUP_XMLFREEURI xmlURIPtr uri = NULL;
|
||||
CLEANUP_FREE char *socket = NULL;
|
||||
|
||||
uri = xmlParseURI (arg);
|
||||
if (!uri) {
|
||||
fprintf (stderr, _("%s: --add: could not parse URI '%s'\n"),
|
||||
program_name, arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Note we don't do much checking of the parsed URI, since the
|
||||
* underlying function 'guestfs_add_drive_opts' will check for us.
|
||||
* So just the basics here.
|
||||
*/
|
||||
if (uri->scheme == NULL || STREQ (uri->scheme, "")) {
|
||||
/* Probably can never happen. */
|
||||
fprintf (stderr, _("%s: %s: scheme of URI is NULL or empty\n"),
|
||||
program_name, arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
socket = query_get (uri, "socket");
|
||||
|
||||
if (uri->server && STRNEQ (uri->server, "") && socket) {
|
||||
fprintf (stderr, _("%s: %s: cannot both a server name and a socket query parameter\n"),
|
||||
program_name, arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is this needed? XXX
|
||||
if (socket && socket[0] != '/') {
|
||||
fprintf (stderr, _("%s: --add %s: socket query parameter must be an absolute path\n"),
|
||||
program_name, arg);
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
*protocol_ret = strdup (uri->scheme);
|
||||
if (*protocol_ret == NULL) {
|
||||
perror ("strdup");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (make_server (uri, socket, server_ret) == -1) {
|
||||
free (*protocol_ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uri->user && STRNEQ (uri->user, "")) {
|
||||
*username_ret = strdup (uri->user);
|
||||
if (*username_ret == NULL) {
|
||||
perror ("username");
|
||||
free (*protocol_ret);
|
||||
guestfs___free_string_list (*server_ret);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else *username_ret = NULL;
|
||||
|
||||
*path_ret = strdup (uri->path ? uri->path : "");
|
||||
if (!*path_ret) {
|
||||
perror ("path");
|
||||
free (*protocol_ret);
|
||||
guestfs___free_string_list (*server_ret);
|
||||
free (*username_ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Code inspired by libvirt src/util/viruri.c, written by danpb,
|
||||
* released under a compatible license.
|
||||
*/
|
||||
static char *
|
||||
query_get (xmlURIPtr uri, const char *search_name)
|
||||
{
|
||||
/* XXX libvirt uses deprecated uri->query field. Why? */
|
||||
const char *query = uri->query_raw;
|
||||
const char *end, *eq;
|
||||
|
||||
if (!query || STREQ (query, ""))
|
||||
return NULL;
|
||||
|
||||
while (*query) {
|
||||
CLEANUP_FREE char *name = NULL;
|
||||
char *value = NULL;
|
||||
|
||||
/* Find the next separator, or end of the string. */
|
||||
end = strchr (query, '&');
|
||||
if (!end)
|
||||
end = strchr(query, ';');
|
||||
if (!end)
|
||||
end = query + strlen (query);
|
||||
|
||||
/* Find the first '=' character between here and end. */
|
||||
eq = strchr(query, '=');
|
||||
if (eq && eq >= end) eq = NULL;
|
||||
|
||||
/* Empty section (eg. "&&"). */
|
||||
if (end == query)
|
||||
goto next;
|
||||
|
||||
/* If there is no '=' character, then we have just "name"
|
||||
* and consistent with CGI.pm we assume value is "".
|
||||
*/
|
||||
else if (!eq) {
|
||||
name = xmlURIUnescapeString (query, end - query, NULL);
|
||||
if (!name) goto no_memory;
|
||||
}
|
||||
/* Or if we have "name=" here (works around annoying
|
||||
* problem when calling xmlURIUnescapeString with len = 0).
|
||||
*/
|
||||
else if (eq+1 == end) {
|
||||
name = xmlURIUnescapeString (query, eq - query, NULL);
|
||||
if (!name) goto no_memory;
|
||||
}
|
||||
/* If the '=' character is at the beginning then we have
|
||||
* "=value" and consistent with CGI.pm we _ignore_ this.
|
||||
*/
|
||||
else if (query == eq)
|
||||
goto next;
|
||||
|
||||
/* Otherwise it's "name=value". */
|
||||
else {
|
||||
name = xmlURIUnescapeString (query, eq - query, NULL);
|
||||
if (!name)
|
||||
goto no_memory;
|
||||
value = xmlURIUnescapeString (eq+1, end - (eq+1), NULL);
|
||||
if (!value) {
|
||||
goto no_memory;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is it the name we're looking for? */
|
||||
if (STREQ (name, search_name)) {
|
||||
if (!value) {
|
||||
value = strdup ("");
|
||||
if (!value)
|
||||
goto no_memory;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
free (value);
|
||||
|
||||
next:
|
||||
query = end;
|
||||
if (*query)
|
||||
query++; /* skip '&' separator */
|
||||
}
|
||||
|
||||
/* search_name not found */
|
||||
return NULL;
|
||||
|
||||
no_memory:
|
||||
perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Construct either a tcp: server list of a unix: server list or
|
||||
* nothing at all from '-a' option URI.
|
||||
*/
|
||||
static int
|
||||
make_server (xmlURIPtr uri, const char *socket, char ***ret)
|
||||
{
|
||||
char *server;
|
||||
|
||||
/* If the server part of the URI is specified, then this is a TCP
|
||||
* connection.
|
||||
*/
|
||||
if (uri->server && STRNEQ (uri->server, "")) {
|
||||
if (uri->port == 0) {
|
||||
if (asprintf (&server, "tcp:%s", uri->server) == -1) {
|
||||
perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (asprintf (&server, "tcp:%s:%d", uri->server, uri->port) == -1) {
|
||||
perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Otherwise, ?socket query parameter means it's a Unix domain
|
||||
* socket connection.
|
||||
*/
|
||||
else if (socket != NULL) {
|
||||
if (asprintf (&server, "unix:%s", socket) == -1) {
|
||||
perror ("asprintf");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* Otherwise, no server parameter is needed. */
|
||||
else {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The .server parameter is in fact a list of strings, although
|
||||
* only a singleton is passed by us.
|
||||
*/
|
||||
*ret = malloc (sizeof (char *) * 2);
|
||||
if (*ret == NULL) {
|
||||
perror ("malloc");
|
||||
return -1;
|
||||
}
|
||||
(*ret)[0] = server;
|
||||
(*ret)[1] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
46
fish/uri.h
Normal file
46
fish/uri.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* libguestfs - mini library for parsing -a URI parameters
|
||||
* Copyright (C) 2013 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifndef FISH_URI_H
|
||||
#define FISH_URI_H
|
||||
|
||||
struct uri {
|
||||
char *path; /* disk path */
|
||||
char *protocol; /* protocol (eg. "file", "nbd") */
|
||||
char **server; /* server(s) - can be NULL */
|
||||
char *username; /* username - can be NULL */
|
||||
};
|
||||
|
||||
/* Parse the '-a' option parameter 'arg', and place the result in
|
||||
* '*uri_ret'.
|
||||
*
|
||||
* If it doesn't look like a URI then uri_ret->path will be the same
|
||||
* as 'arg' (copied) and uri_ret->protocol will be "file".
|
||||
*
|
||||
* If it looks like a URI and can be parsed, then the other fields will
|
||||
* be filled in as appropriate.
|
||||
*
|
||||
* The caller should free the fields from the struct after use.
|
||||
*
|
||||
* Returns 0 if parsing went OK, or -1 if there was an error.
|
||||
*/
|
||||
extern int parse_uri (const char *arg, struct uri *uri_ret);
|
||||
|
||||
#endif /* FISH_URI_H */
|
||||
@@ -30,7 +30,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
virt_format_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
|
||||
@@ -42,7 +42,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
# guestmount
|
||||
|
||||
|
||||
@@ -57,7 +57,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
virt_inspector_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
|
||||
@@ -199,7 +199,11 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->a.filename = argv[optind];
|
||||
drv->a.filename = strdup (argv[optind]);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
} else { /* simulate -d option */
|
||||
|
||||
@@ -145,6 +145,7 @@ fish/setenv.c
|
||||
fish/supported.c
|
||||
fish/tilde.c
|
||||
fish/time.c
|
||||
fish/uri.c
|
||||
format/format.c
|
||||
fuse/guestmount.c
|
||||
fuse/guestunmount.c
|
||||
|
||||
@@ -31,7 +31,9 @@ SHARED_SOURCE_FILES = \
|
||||
../fish/inspect.c \
|
||||
../fish/keys.c \
|
||||
../fish/options.h \
|
||||
../fish/options.c
|
||||
../fish/options.c \
|
||||
../fish/uri.h \
|
||||
../fish/uri.c
|
||||
|
||||
virt_rescue_SOURCES = \
|
||||
$(SHARED_SOURCE_FILES) \
|
||||
|
||||
@@ -256,7 +256,11 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->a.filename = argv[optind];
|
||||
drv->a.filename = strdup (argv[optind]);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
} else { /* simulate -d option */
|
||||
@@ -570,7 +574,11 @@ add_scratch_disk (struct drv **drvs)
|
||||
}
|
||||
drv->type = drv_a;
|
||||
drv->nr_drives = -1;
|
||||
drv->a.filename = filename;
|
||||
drv->a.filename = strdup (filename);
|
||||
if (!drv->a.filename) {
|
||||
perror ("strdup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->a.format = "raw";
|
||||
drv->next = *drvs;
|
||||
*drvs = drv;
|
||||
|
||||
Reference in New Issue
Block a user