* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
+
+#include "qemu/osdep.h"
#include <sys/socket.h>
#include <sys/un.h>
#include "9p.h"
+#include "qapi/error.h"
+#include "qemu/cutils.h"
#include "qemu/error-report.h"
+#include "qemu/option.h"
#include "fsdev/qemu-fsdev.h"
#include "9p-proxy.h"
return retval;
}
reply->iov_len = PROXY_HDR_SZ;
- proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
+ retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
+ assert(retval == 4 * 2);
/*
* if response size > PROXY_MAX_IO_SZ, read the response but ignore it and
* return -ENOBUFS
if (header.type == T_ERROR) {
int ret;
ret = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
- if (ret < 0) {
- *status = ret;
- }
+ assert(ret == 4);
return 0;
}
&prstat.st_atim_sec, &prstat.st_atim_nsec,
&prstat.st_mtim_sec, &prstat.st_mtim_nsec,
&prstat.st_ctim_sec, &prstat.st_ctim_nsec);
+ assert(retval == 8 * 3 + 4 * 3 + 8 * 10);
prstat_to_stat(response, &prstat);
break;
}
&prstfs.f_files, &prstfs.f_ffree,
&prstfs.f_fsid[0], &prstfs.f_fsid[1],
&prstfs.f_namelen, &prstfs.f_frsize);
+ assert(retval == 8 * 11);
prstatfs_to_statfs(response, &prstfs);
break;
}
break;
}
case T_GETVERSION:
- proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
+ retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "q", response);
+ assert(retval == 8);
break;
default:
return -1;
return retval;
}
reply->iov_len = PROXY_HDR_SZ;
- proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
- if (header.size != sizeof(int)) {
- *status = -ENOBUFS;
- return 0;
- }
+ retval = proxy_unmarshal(reply, 0, "dd", &header.type, &header.size);
+ assert(retval == 4 * 2);
retval = socket_read(proxy->sockfd,
reply->iov_base + PROXY_HDR_SZ, header.size);
if (retval < 0) {
return retval;
}
reply->iov_len += header.size;
- proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
+ retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "d", status);
+ assert(retval == 4);
return 0;
}
* This request read by proxy helper process
* returns 0 on success and -errno on error
*/
-static int v9fs_request(V9fsProxy *proxy, int type,
- void *response, const char *fmt, ...)
+static int v9fs_request(V9fsProxy *proxy, int type, void *response, ...)
{
dev_t rdev;
va_list ap;
}
iovec = &proxy->out_iovec;
reply = &proxy->in_iovec;
- va_start(ap, fmt);
+ va_start(ap, response);
switch (type) {
case T_OPEN:
path = va_arg(ap, V9fsString *);
static int proxy_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, "s", fs_path);
+ retval = v9fs_request(fs_ctx->private, T_LSTAT, stbuf, fs_path);
if (retval < 0) {
errno = -retval;
return -1;
char *buf, size_t bufsz)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_READLINK, buf, "sd",
- fs_path, bufsz);
+ retval = v9fs_request(fs_ctx->private, T_READLINK, buf, fs_path, bufsz);
if (retval < 0) {
errno = -retval;
return -1;
static int proxy_closedir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return closedir(fs->dir);
+ return closedir(fs->dir.stream);
}
static int proxy_open(FsContext *ctx, V9fsPath *fs_path,
int flags, V9fsFidOpenState *fs)
{
- fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, flags);
+ fs->fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, flags);
if (fs->fd < 0) {
errno = -fs->fd;
fs->fd = -1;
{
int serrno, fd;
- fs->dir = NULL;
- fd = v9fs_request(ctx->private, T_OPEN, NULL, "sd", fs_path, O_DIRECTORY);
+ fs->dir.stream = NULL;
+ fd = v9fs_request(ctx->private, T_OPEN, NULL, fs_path, O_DIRECTORY);
if (fd < 0) {
errno = -fd;
return -1;
}
- fs->dir = fdopendir(fd);
- if (!fs->dir) {
+ fs->dir.stream = fdopendir(fd);
+ if (!fs->dir.stream) {
serrno = errno;
close(fd);
errno = serrno;
static void proxy_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
{
- rewinddir(fs->dir);
+ rewinddir(fs->dir.stream);
}
static off_t proxy_telldir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return telldir(fs->dir);
+ return telldir(fs->dir.stream);
}
-static int proxy_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
- struct dirent *entry,
- struct dirent **result)
+static struct dirent *proxy_readdir(FsContext *ctx, V9fsFidOpenState *fs)
{
- return readdir_r(fs->dir, entry, result);
+ return readdir(fs->dir.stream);
}
static void proxy_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
{
- seekdir(fs->dir, off);
+ seekdir(fs->dir.stream, off);
}
static ssize_t proxy_preadv(FsContext *ctx, V9fsFidOpenState *fs,
static int proxy_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, "sd",
- fs_path, credp->fc_mode);
+ retval = v9fs_request(fs_ctx->private, T_CHMOD, NULL, fs_path,
+ credp->fc_mode);
if (retval < 0) {
errno = -retval;
}
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, "sdqdd",
- &fullname, credp->fc_mode, credp->fc_rdev,
+ retval = v9fs_request(fs_ctx->private, T_MKNOD, NULL, &fullname,
+ credp->fc_mode, credp->fc_rdev,
credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
if (retval < 0) {
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, "sddd", &fullname,
+ retval = v9fs_request(fs_ctx->private, T_MKDIR, NULL, &fullname,
credp->fc_mode, credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
if (retval < 0) {
errno = -retval;
retval = -1;
}
- v9fs_string_free(&fullname);
return retval;
}
int fd;
if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
+ fd = dirfd(fs->dir.stream);
} else {
fd = fs->fd;
}
v9fs_string_init(&fullname);
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
- fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, "sdddd",
- &fullname, flags, credp->fc_mode,
- credp->fc_uid, credp->fc_gid);
+ fs->fd = v9fs_request(fs_ctx->private, T_CREATE, NULL, &fullname, flags,
+ credp->fc_mode, credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
if (fs->fd < 0) {
errno = -fs->fd;
v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name);
v9fs_string_sprintf(&target, "%s", oldpath);
- retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, "ssdd",
- &target, &fullname, credp->fc_uid, credp->fc_gid);
+ retval = v9fs_request(fs_ctx->private, T_SYMLINK, NULL, &target, &fullname,
+ credp->fc_uid, credp->fc_gid);
v9fs_string_free(&fullname);
v9fs_string_free(&target);
if (retval < 0) {
v9fs_string_init(&newpath);
v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name);
- retval = v9fs_request(ctx->private, T_LINK, NULL, "ss", oldpath, &newpath);
+ retval = v9fs_request(ctx->private, T_LINK, NULL, oldpath, &newpath);
v9fs_string_free(&newpath);
if (retval < 0) {
errno = -retval;
{
int retval;
- retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, "sq", fs_path, size);
+ retval = v9fs_request(ctx->private, T_TRUNCATE, NULL, fs_path, size);
if (retval < 0) {
errno = -retval;
return -1;
v9fs_string_sprintf(&oldname, "%s", oldpath);
v9fs_string_sprintf(&newname, "%s", newpath);
- retval = v9fs_request(ctx->private, T_RENAME, NULL, "ss",
- &oldname, &newname);
+ retval = v9fs_request(ctx->private, T_RENAME, NULL, &oldname, &newname);
v9fs_string_free(&oldname);
v9fs_string_free(&newname);
if (retval < 0) {
static int proxy_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
int retval;
- retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, "sdd",
- fs_path, credp->fc_uid, credp->fc_gid);
+ retval = v9fs_request(fs_ctx->private, T_CHOWN, NULL, fs_path,
+ credp->fc_uid, credp->fc_gid);
if (retval < 0) {
errno = -retval;
}
const struct timespec *buf)
{
int retval;
- retval = v9fs_request(s->private, T_UTIME, NULL, "sqqqq",
- fs_path,
+ retval = v9fs_request(s->private, T_UTIME, NULL, fs_path,
buf[0].tv_sec, buf[0].tv_nsec,
buf[1].tv_sec, buf[1].tv_nsec);
if (retval < 0) {
V9fsString name;
v9fs_string_init(&name);
v9fs_string_sprintf(&name, "%s", path);
- retval = v9fs_request(ctx->private, T_REMOVE, NULL, "s", &name);
+ retval = v9fs_request(ctx->private, T_REMOVE, NULL, &name);
v9fs_string_free(&name);
if (retval < 0) {
errno = -retval;
int fd;
if (fid_type == P9_FID_DIR) {
- fd = dirfd(fs->dir);
+ fd = dirfd(fs->dir.stream);
} else {
fd = fs->fd;
}
static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf)
{
int retval;
- retval = v9fs_request(s->private, T_STATFS, stbuf, "s", fs_path);
+ retval = v9fs_request(s->private, T_STATFS, stbuf, fs_path);
if (retval < 0) {
errno = -retval;
return -1;
v9fs_string_init(&xname);
v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size,
- fs_path, &xname);
+ retval = v9fs_request(ctx->private, T_LGETXATTR, value, size, fs_path,
+ &xname);
v9fs_string_free(&xname);
if (retval < 0) {
errno = -retval;
void *value, size_t size)
{
int retval;
- retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size,
- fs_path);
+ retval = v9fs_request(ctx->private, T_LLISTXATTR, value, size, fs_path);
if (retval < 0) {
errno = -retval;
}
xvalue.data = g_malloc(size);
memcpy(xvalue.data, value, size);
- retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd",
- fs_path, &xname, &xvalue, size, flags);
+ retval = v9fs_request(ctx->private, T_LSETXATTR, value, fs_path, &xname,
+ &xvalue, size, flags);
v9fs_string_free(&xname);
v9fs_string_free(&xvalue);
if (retval < 0) {
v9fs_string_init(&xname);
v9fs_string_sprintf(&xname, "%s", name);
- retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss",
- fs_path, &xname);
+ retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, fs_path, &xname);
v9fs_string_free(&xname);
if (retval < 0) {
errno = -retval;
const char *name, V9fsPath *target)
{
if (dir_path) {
- v9fs_string_sprintf((V9fsString *)target, "%s/%s",
- dir_path->data, name);
+ v9fs_path_sprintf(target, "%s/%s", dir_path->data, name);
} else {
- v9fs_string_sprintf((V9fsString *)target, "%s", name);
+ v9fs_path_sprintf(target, "%s", name);
}
- /* Bump the size for including terminating NULL */
- target->size++;
return 0;
}
errno = ENOTTY;
return -1;
}
- err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, "s", path);
+ err = v9fs_request(fs_ctx->private, T_GETVERSION, st_gen, path);
if (err < 0) {
errno = -err;
err = -1;
return err;
}
-static int connect_namedsocket(const char *path)
+static int connect_namedsocket(const char *path, Error **errp)
{
int sockfd, size;
struct sockaddr_un helper;
if (strlen(path) >= sizeof(helper.sun_path)) {
- error_report("Socket name too long");
+ error_setg(errp, "socket name too long");
return -1;
}
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
- error_report("Failed to create socket: %s", strerror(errno));
+ error_setg_errno(errp, errno, "failed to create client socket");
return -1;
}
strcpy(helper.sun_path, path);
helper.sun_family = AF_UNIX;
size = strlen(helper.sun_path) + sizeof(helper.sun_family);
if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) {
- error_report("Failed to connect to %s: %s", path, strerror(errno));
+ error_setg_errno(errp, errno, "failed to connect to '%s'", path);
close(sockfd);
return -1;
}
return sockfd;
}
-static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
+static void error_append_socket_sockfd_hint(Error **errp)
+{
+ error_append_hint(errp, "Either specify socket=/some/path where /some/path"
+ " points to a listening AF_UNIX socket or sock_fd=fd"
+ " where fd is a file descriptor to a connected AF_UNIX"
+ " socket\n");
+}
+
+static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp)
{
const char *socket = qemu_opt_get(opts, "socket");
const char *sock_fd = qemu_opt_get(opts, "sock_fd");
if (!socket && !sock_fd) {
- error_report("Must specify either socket or sock_fd");
+ error_setg(errp, "both socket and sock_fd properties are missing");
+ error_append_socket_sockfd_hint(errp);
return -1;
}
if (socket && sock_fd) {
- error_report("Both socket and sock_fd options specified");
+ error_setg(errp, "both socket and sock_fd properties are set");
+ error_append_socket_sockfd_hint(errp);
return -1;
}
if (socket) {
return 0;
}
-static int proxy_init(FsContext *ctx)
+static int proxy_init(FsContext *ctx, Error **errp)
{
V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
int sock_id;
if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
- sock_id = connect_namedsocket(ctx->fs_root);
+ sock_id = connect_namedsocket(ctx->fs_root, errp);
} else {
sock_id = atoi(ctx->fs_root);
if (sock_id < 0) {
- error_report("Socket descriptor not initialized");
+ error_setg(errp, "socket descriptor not initialized");
}
}
if (sock_id < 0) {
return 0;
}
+static void proxy_cleanup(FsContext *ctx)
+{
+ V9fsProxy *proxy = ctx->private;
+
+ g_free(proxy->out_iovec.iov_base);
+ g_free(proxy->in_iovec.iov_base);
+ if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
+ close(proxy->sockfd);
+ }
+ g_free(proxy);
+}
+
FileOperations proxy_ops = {
.parse_opts = proxy_parse_opts,
.init = proxy_init,
+ .cleanup = proxy_cleanup,
.lstat = proxy_lstat,
.readlink = proxy_readlink,
.close = proxy_close,
.opendir = proxy_opendir,
.rewinddir = proxy_rewinddir,
.telldir = proxy_telldir,
- .readdir_r = proxy_readdir_r,
+ .readdir = proxy_readdir,
.seekdir = proxy_seekdir,
.preadv = proxy_preadv,
.pwritev = proxy_pwritev,