The abstract socket namespace is a nonportable Linux extension. The sockets' names in this namespace have no connection with file system pathnames. To specify a named AF_UNIX socket in the abstract socket namespace, start the socket's path option with a backslash followed by zero: \0.
Signed-off-by: Alexander Barabash <alexander_barab...@mentor.com> --- qemu-sockets.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/qemu-sockets.c b/qemu-sockets.c index 3537bf3..70c8ad5 100644 --- a/qemu-sockets.c +++ b/qemu-sockets.c @@ -663,11 +663,50 @@ int inet_nonblocking_connect(const char *str, #ifndef _WIN32 +/* + * The abstract socket namespace is a nonportable Linux extension. + * The sockets' names in this namespace have no connection + * with file system pathnames. To specify a named AF_UNIX socket + * in the abstract socket namespace, start the socket's path option + * with a backslash followed by zero: \0. + */ +static +char *get_abstract_namespace_path(const char *path, int *abstract_path_length) +{ + char *abstract_path; + char *inp; + char *outp; + char c; + + *abstract_path_length = 0; + if ((path == NULL) || (path[0] != '\\') || (path[1] != '0')) { + return NULL; + } + abstract_path = g_strdup(path + 2); + for (inp = abstract_path, outp = abstract_path; (c = *inp); ++inp, ++outp) { + if (c == '\\') { + c = *++inp; + if (c == '\\') { + *outp = c; + } else if (c == '0') { + *outp = '\0'; + } + } else { + *outp = c; + } + } + *abstract_path_length = outp - abstract_path; + return abstract_path; +} + int unix_listen_opts(QemuOpts *opts, Error **errp) { struct sockaddr_un un; const char *path = qemu_opt_get(opts, "path"); + int abstract_path_length; + char *abstract_path; int sock, fd; + socklen_t addrlen = sizeof(un); sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { @@ -675,9 +714,18 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) return -1; } + abstract_path = get_abstract_namespace_path(path, &abstract_path_length); + memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - if (path && strlen(path)) { + if (abstract_path != NULL) { + if (abstract_path_length > sizeof(un.sun_path) - 1) { + abstract_path_length = sizeof(un.sun_path) - 1; + } + memcpy(un.sun_path + 1, abstract_path, abstract_path_length); + addrlen = + offsetof(struct sockaddr_un, sun_path) + 1 + abstract_path_length; + } else if (path && strlen(path)) { snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); } else { char *tmpdir = getenv("TMPDIR"); @@ -694,8 +742,10 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) qemu_opt_set(opts, "path", un.sun_path); } - unlink(un.sun_path); - if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { + if (abstract_path == NULL) { + unlink(un.sun_path); + } + if (bind(sock, (struct sockaddr *) &un, addrlen) < 0) { error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); goto err; } @@ -704,10 +754,12 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) goto err; } + g_free(abstract_path); return sock; err: closesocket(sock); + g_free(abstract_path); return -1; } -- 1.7.9.5