mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
fish: options: Allow Unix domain sockets to be specified in --add URIs.
You can now use a URI such as: guestfish -a nbd://?socket=/tmp/sock (a NBD connection to Unix domain socket /tmp/sock).
This commit is contained in:
@@ -1102,7 +1102,7 @@ block devices using a URI-style format, for example:
|
||||
URIs I<cannot> be used with the L</add> command. The equivalent
|
||||
command using the API directly is:
|
||||
|
||||
><fs> add /disk.img protocol:ssh server:example.com username:root
|
||||
><fs> add /disk.img protocol:ssh server:tcp:example.com username:root
|
||||
|
||||
The possible I<-a URI> formats are described below.
|
||||
|
||||
@@ -1120,19 +1120,28 @@ The server is the one running C<glusterd>, and may be C<localhost>.
|
||||
|
||||
The equivalent API command would be:
|
||||
|
||||
><fs> add /disk protocol:gluster server:example.com
|
||||
><fs> add /disk protocol:gluster server:tcp:example.com
|
||||
|
||||
=head2 B<-a nbd://example.com[:port][/exportname]>
|
||||
=head2 B<-a nbd://example.com[:port]>
|
||||
|
||||
=head2 B<-a nbd://example.com[:port]/exportname>
|
||||
|
||||
=head2 B<-a nbd://?socket=/socket>
|
||||
|
||||
=head2 B<-a nbd:///exportname?socket=/socket>
|
||||
|
||||
Add a disk located on Network Block Device (nbd) storage.
|
||||
|
||||
The URI syntax only supports TCP. Libguestfs can use Unix domain
|
||||
sockets if you use the L</add> API directly. The I</exportname> part
|
||||
of the URI specifies an NBD export name, but is usually left empty.
|
||||
The I</exportname> part of the URI specifies an NBD export name, but
|
||||
is usually left empty.
|
||||
|
||||
The optional I<?socket> parameter can be used to specify a Unix domain
|
||||
socket that we talk to the NBD server over. Note that you cannot mix
|
||||
server name (ie. TCP/IP) and socket path.
|
||||
|
||||
The equivalent API command would be (no export name):
|
||||
|
||||
><fs> add "" protocol:nbd server:example.com
|
||||
><fs> add "" protocol:nbd server:[tcp:example.com|unix:/socket]
|
||||
|
||||
=head2 B<-a rbd://example.com[:port]/disk>
|
||||
|
||||
@@ -1143,7 +1152,7 @@ server can be specified when using this URI syntax.
|
||||
|
||||
The equivalent API command would be:
|
||||
|
||||
><fs> add /disk protocol:rbd server:example.com
|
||||
><fs> add /disk protocol:rbd server:tcp:example.com
|
||||
|
||||
=head2 B<-a sheepdog://[example.com[:port]]/volume/image>
|
||||
|
||||
@@ -1155,7 +1164,7 @@ when using this URI syntax.
|
||||
|
||||
The equivalent API command would be:
|
||||
|
||||
><fs> add /disk protocol:sheepdog [server:example.com]
|
||||
><fs> add /disk protocol:sheepdog [server:tcp:example.com]
|
||||
|
||||
=head2 B<-a ssh://[user@]example.com[:port]/disk.img>
|
||||
|
||||
@@ -1165,7 +1174,7 @@ major SSH servers.
|
||||
|
||||
The equivalent API command would be:
|
||||
|
||||
><fs> add /disk protocol:ssh server:example.com [username:user]
|
||||
><fs> add /disk protocol:ssh server:tcp:example.com [username:user]
|
||||
|
||||
=head1 PROGRESS BARS
|
||||
|
||||
|
||||
158
fish/options.c
158
fish/options.c
@@ -35,6 +35,7 @@
|
||||
|
||||
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);
|
||||
|
||||
/* Handle the '-a' option when passed on the command line. */
|
||||
void
|
||||
@@ -96,6 +97,7 @@ static void
|
||||
parse_uri (const char *arg, const char *format, struct drv *drv)
|
||||
{
|
||||
xmlURIPtr uri;
|
||||
char *socket;
|
||||
|
||||
uri = xmlParseURI (arg);
|
||||
if (!uri) {
|
||||
@@ -110,35 +112,160 @@ parse_uri (const char *arg, const char *format, struct drv *drv)
|
||||
*/
|
||||
if (uri->scheme == NULL) {
|
||||
/* Probably can never happen. */
|
||||
fprintf (stderr, _("%s: --add: scheme of URI '%s' is NULL\n"),
|
||||
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);
|
||||
}
|
||||
*/
|
||||
|
||||
drv->type = drv_uri;
|
||||
drv->nr_drives = -1;
|
||||
drv->uri.uri = uri;
|
||||
drv->uri.socket = socket;
|
||||
drv->uri.format = format;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
make_server (xmlURIPtr uri, const char *socket)
|
||||
{
|
||||
char **ret;
|
||||
char *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) {
|
||||
/* 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.
|
||||
@@ -155,6 +282,7 @@ add_drives (struct drv *drv, char next_drive)
|
||||
{
|
||||
int r;
|
||||
struct guestfs_add_drive_opts_argv ad_optargs;
|
||||
char **server;
|
||||
|
||||
if (next_drive > 'z') {
|
||||
fprintf (stderr,
|
||||
@@ -206,12 +334,9 @@ add_drives (struct drv *drv, char next_drive)
|
||||
}
|
||||
ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_PROTOCOL_BITMASK;
|
||||
ad_optargs.protocol = drv->uri.uri->scheme;
|
||||
if (drv->uri.uri->server && STRNEQ (drv->uri.uri->server, "")) {
|
||||
ad_optargs.server = server = make_server (drv->uri.uri, drv->uri.socket);
|
||||
if (server)
|
||||
ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_SERVER_BITMASK;
|
||||
ad_optargs.server = make_server (drv->uri.uri);
|
||||
}
|
||||
else
|
||||
ad_optargs.server = NULL;
|
||||
if (drv->uri.uri->user && STRNEQ (drv->uri.uri->user, "")) {
|
||||
ad_optargs.bitmask |= GUESTFS_ADD_DRIVE_OPTS_USERNAME_BITMASK;
|
||||
ad_optargs.username = drv->uri.uri->user;
|
||||
@@ -222,7 +347,7 @@ add_drives (struct drv *drv, char next_drive)
|
||||
if (r == -1)
|
||||
exit (EXIT_FAILURE);
|
||||
|
||||
guestfs___free_string_list ((char **) ad_optargs.server);
|
||||
guestfs___free_string_list (server);
|
||||
|
||||
drv->nr_drives = 1;
|
||||
next_drive++;
|
||||
@@ -334,6 +459,7 @@ free_drives (struct drv *drv)
|
||||
break;
|
||||
case drv_uri:
|
||||
xmlFreeURI (drv->uri.uri);
|
||||
free (drv->uri.socket);
|
||||
break;
|
||||
case drv_d:
|
||||
/* d.filename is optarg, don't free it */
|
||||
|
||||
@@ -65,6 +65,7 @@ struct drv {
|
||||
} a;
|
||||
struct {
|
||||
xmlURIPtr uri; /* URI */
|
||||
char *socket; /* ?socket parameter from URI. */
|
||||
const char *format; /* format (NULL == autodetect) */
|
||||
} uri;
|
||||
struct {
|
||||
|
||||
Reference in New Issue
Block a user