monitor: Split file descriptor passing stuff off misc.c
Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20230124121946.1139465-27-armbru@redhat.com>
This commit is contained in:
parent
9c9c5ce7f7
commit
7ef88b5334
468
monitor/fds.c
Normal file
468
monitor/fds.c
Normal file
@ -0,0 +1,468 @@
|
||||
/*
|
||||
* QEMU monitor file descriptor passing
|
||||
*
|
||||
* Copyright (c) 2003-2004 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "monitor-internal.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/ctype.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
/* file descriptors passed via SCM_RIGHTS */
|
||||
typedef struct mon_fd_t mon_fd_t;
|
||||
struct mon_fd_t {
|
||||
char *name;
|
||||
int fd;
|
||||
QLIST_ENTRY(mon_fd_t) next;
|
||||
};
|
||||
|
||||
/* file descriptor associated with a file descriptor set */
|
||||
typedef struct MonFdsetFd MonFdsetFd;
|
||||
struct MonFdsetFd {
|
||||
int fd;
|
||||
bool removed;
|
||||
char *opaque;
|
||||
QLIST_ENTRY(MonFdsetFd) next;
|
||||
};
|
||||
|
||||
/* file descriptor set containing fds passed via SCM_RIGHTS */
|
||||
typedef struct MonFdset MonFdset;
|
||||
struct MonFdset {
|
||||
int64_t id;
|
||||
QLIST_HEAD(, MonFdsetFd) fds;
|
||||
QLIST_HEAD(, MonFdsetFd) dup_fds;
|
||||
QLIST_ENTRY(MonFdset) next;
|
||||
};
|
||||
|
||||
/* Protects mon_fdsets */
|
||||
static QemuMutex mon_fdsets_lock;
|
||||
static QLIST_HEAD(, MonFdset) mon_fdsets;
|
||||
|
||||
void qmp_getfd(const char *fdname, Error **errp)
|
||||
{
|
||||
Monitor *cur_mon = monitor_cur();
|
||||
mon_fd_t *monfd;
|
||||
int fd, tmp_fd;
|
||||
|
||||
fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
|
||||
if (fd == -1) {
|
||||
error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
|
||||
return;
|
||||
}
|
||||
|
||||
if (qemu_isdigit(fdname[0])) {
|
||||
close(fd);
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
|
||||
"a name not starting with a digit");
|
||||
return;
|
||||
}
|
||||
|
||||
QEMU_LOCK_GUARD(&cur_mon->mon_lock);
|
||||
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
||||
if (strcmp(monfd->name, fdname) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp_fd = monfd->fd;
|
||||
monfd->fd = fd;
|
||||
/* Make sure close() is outside critical section */
|
||||
close(tmp_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
monfd = g_new0(mon_fd_t, 1);
|
||||
monfd->name = g_strdup(fdname);
|
||||
monfd->fd = fd;
|
||||
|
||||
QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next);
|
||||
}
|
||||
|
||||
void qmp_closefd(const char *fdname, Error **errp)
|
||||
{
|
||||
Monitor *cur_mon = monitor_cur();
|
||||
mon_fd_t *monfd;
|
||||
int tmp_fd;
|
||||
|
||||
qemu_mutex_lock(&cur_mon->mon_lock);
|
||||
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
||||
if (strcmp(monfd->name, fdname) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QLIST_REMOVE(monfd, next);
|
||||
tmp_fd = monfd->fd;
|
||||
g_free(monfd->name);
|
||||
g_free(monfd);
|
||||
qemu_mutex_unlock(&cur_mon->mon_lock);
|
||||
/* Make sure close() is outside critical section */
|
||||
close(tmp_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&cur_mon->mon_lock);
|
||||
error_setg(errp, "File descriptor named '%s' not found", fdname);
|
||||
}
|
||||
|
||||
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
|
||||
{
|
||||
mon_fd_t *monfd;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon->mon_lock);
|
||||
QLIST_FOREACH(monfd, &mon->fds, next) {
|
||||
int fd;
|
||||
|
||||
if (strcmp(monfd->name, fdname) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = monfd->fd;
|
||||
assert(fd >= 0);
|
||||
|
||||
/* caller takes ownership of fd */
|
||||
QLIST_REMOVE(monfd, next);
|
||||
g_free(monfd->name);
|
||||
g_free(monfd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
error_setg(errp, "File descriptor named '%s' has not been found", fdname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void monitor_fdset_cleanup(MonFdset *mon_fdset)
|
||||
{
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
MonFdsetFd *mon_fdset_fd_next;
|
||||
|
||||
QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) {
|
||||
if ((mon_fdset_fd->removed ||
|
||||
(QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) &&
|
||||
runstate_is_running()) {
|
||||
close(mon_fdset_fd->fd);
|
||||
g_free(mon_fdset_fd->opaque);
|
||||
QLIST_REMOVE(mon_fdset_fd, next);
|
||||
g_free(mon_fdset_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
||||
QLIST_REMOVE(mon_fdset, next);
|
||||
g_free(mon_fdset);
|
||||
}
|
||||
}
|
||||
|
||||
void monitor_fdsets_cleanup(void)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdset *mon_fdset_next;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
|
||||
monitor_fdset_cleanup(mon_fdset);
|
||||
}
|
||||
}
|
||||
|
||||
AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id,
|
||||
const char *opaque, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
Monitor *mon = monitor_cur();
|
||||
AddfdInfo *fdinfo;
|
||||
|
||||
fd = qemu_chr_fe_get_msgfd(&mon->chr);
|
||||
if (fd == -1) {
|
||||
error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
|
||||
goto error;
|
||||
}
|
||||
|
||||
fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp);
|
||||
if (fdinfo) {
|
||||
return fdinfo;
|
||||
}
|
||||
|
||||
error:
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
char fd_str[60];
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
if (mon_fdset->id != fdset_id) {
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
||||
if (has_fd) {
|
||||
if (mon_fdset_fd->fd != fd) {
|
||||
continue;
|
||||
}
|
||||
mon_fdset_fd->removed = true;
|
||||
break;
|
||||
} else {
|
||||
mon_fdset_fd->removed = true;
|
||||
}
|
||||
}
|
||||
if (has_fd && !mon_fdset_fd) {
|
||||
goto error;
|
||||
}
|
||||
monitor_fdset_cleanup(mon_fdset);
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
if (has_fd) {
|
||||
snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
|
||||
fdset_id, fd);
|
||||
} else {
|
||||
snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
|
||||
}
|
||||
error_setg(errp, "File descriptor named '%s' not found", fd_str);
|
||||
}
|
||||
|
||||
FdsetInfoList *qmp_query_fdsets(Error **errp)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
FdsetInfoList *fdset_list = NULL;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info));
|
||||
|
||||
fdset_info->fdset_id = mon_fdset->id;
|
||||
|
||||
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
||||
FdsetFdInfo *fdsetfd_info;
|
||||
|
||||
fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
|
||||
fdsetfd_info->fd = mon_fdset_fd->fd;
|
||||
fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque);
|
||||
|
||||
QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info);
|
||||
}
|
||||
|
||||
QAPI_LIST_PREPEND(fdset_list, fdset_info);
|
||||
}
|
||||
|
||||
return fdset_list;
|
||||
}
|
||||
|
||||
AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
|
||||
const char *opaque, Error **errp)
|
||||
{
|
||||
MonFdset *mon_fdset = NULL;
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
AddfdInfo *fdinfo;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
if (has_fdset_id) {
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
/* Break if match found or match impossible due to ordering by ID */
|
||||
if (fdset_id <= mon_fdset->id) {
|
||||
if (fdset_id < mon_fdset->id) {
|
||||
mon_fdset = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mon_fdset == NULL) {
|
||||
int64_t fdset_id_prev = -1;
|
||||
MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
|
||||
|
||||
if (has_fdset_id) {
|
||||
if (fdset_id < 0) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
|
||||
"a non-negative value");
|
||||
return NULL;
|
||||
}
|
||||
/* Use specified fdset ID */
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
mon_fdset_cur = mon_fdset;
|
||||
if (fdset_id < mon_fdset_cur->id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Use first available fdset ID */
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
mon_fdset_cur = mon_fdset;
|
||||
if (fdset_id_prev == mon_fdset_cur->id - 1) {
|
||||
fdset_id_prev = mon_fdset_cur->id;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mon_fdset = g_malloc0(sizeof(*mon_fdset));
|
||||
if (has_fdset_id) {
|
||||
mon_fdset->id = fdset_id;
|
||||
} else {
|
||||
mon_fdset->id = fdset_id_prev + 1;
|
||||
}
|
||||
|
||||
/* The fdset list is ordered by fdset ID */
|
||||
if (!mon_fdset_cur) {
|
||||
QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
|
||||
} else if (mon_fdset->id < mon_fdset_cur->id) {
|
||||
QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
|
||||
} else {
|
||||
QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
|
||||
}
|
||||
}
|
||||
|
||||
mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
|
||||
mon_fdset_fd->fd = fd;
|
||||
mon_fdset_fd->removed = false;
|
||||
mon_fdset_fd->opaque = g_strdup(opaque);
|
||||
QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
|
||||
|
||||
fdinfo = g_malloc0(sizeof(*fdinfo));
|
||||
fdinfo->fdset_id = mon_fdset->id;
|
||||
fdinfo->fd = mon_fdset_fd->fd;
|
||||
|
||||
return fdinfo;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return -ENOENT;
|
||||
#else
|
||||
MonFdset *mon_fdset;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
MonFdsetFd *mon_fdset_fd_dup;
|
||||
int fd = -1;
|
||||
int dup_fd;
|
||||
int mon_fd_flags;
|
||||
|
||||
if (mon_fdset->id != fdset_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
||||
mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
|
||||
if (mon_fd_flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
|
||||
fd = mon_fdset_fd->fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dup_fd = qemu_dup_flags(fd, flags);
|
||||
if (dup_fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
|
||||
mon_fdset_fd_dup->fd = dup_fd;
|
||||
QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
|
||||
return dup_fd;
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd_dup;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
|
||||
if (mon_fdset_fd_dup->fd == dup_fd) {
|
||||
if (remove) {
|
||||
QLIST_REMOVE(mon_fdset_fd_dup, next);
|
||||
g_free(mon_fdset_fd_dup);
|
||||
if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
||||
monitor_fdset_cleanup(mon_fdset);
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
return mon_fdset->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t monitor_fdset_dup_fd_find(int dup_fd)
|
||||
{
|
||||
return monitor_fdset_dup_fd_find_remove(dup_fd, false);
|
||||
}
|
||||
|
||||
void monitor_fdset_dup_fd_remove(int dup_fd)
|
||||
{
|
||||
monitor_fdset_dup_fd_find_remove(dup_fd, true);
|
||||
}
|
||||
|
||||
int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!qemu_isdigit(fdname[0]) && mon) {
|
||||
fd = monitor_get_fd(mon, fdname, errp);
|
||||
} else {
|
||||
fd = qemu_parse_fd(fdname);
|
||||
if (fd < 0) {
|
||||
error_setg(errp, "Invalid file descriptor number '%s'",
|
||||
fdname);
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void __attribute__((__constructor__)) monitor_fds_init(void)
|
||||
{
|
||||
qemu_mutex_init(&mon_fdsets_lock);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
qmp_ss.add(files('monitor.c', 'qmp.c', 'qmp-cmds-control.c'))
|
||||
|
||||
softmmu_ss.add(files(
|
||||
'fds.c',
|
||||
'hmp-cmds.c',
|
||||
'hmp.c',
|
||||
))
|
||||
|
434
monitor/misc.c
434
monitor/misc.c
@ -27,11 +27,9 @@
|
||||
#include "monitor/qdev.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "net/slirp.h"
|
||||
#include "qemu/ctype.h"
|
||||
#include "disas/disas.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
@ -56,36 +54,6 @@
|
||||
/* Make devices configuration available for use in hmp-commands*.hx templates */
|
||||
#include CONFIG_DEVICES
|
||||
|
||||
/* file descriptors passed via SCM_RIGHTS */
|
||||
typedef struct mon_fd_t mon_fd_t;
|
||||
struct mon_fd_t {
|
||||
char *name;
|
||||
int fd;
|
||||
QLIST_ENTRY(mon_fd_t) next;
|
||||
};
|
||||
|
||||
/* file descriptor associated with a file descriptor set */
|
||||
typedef struct MonFdsetFd MonFdsetFd;
|
||||
struct MonFdsetFd {
|
||||
int fd;
|
||||
bool removed;
|
||||
char *opaque;
|
||||
QLIST_ENTRY(MonFdsetFd) next;
|
||||
};
|
||||
|
||||
/* file descriptor set containing fds passed via SCM_RIGHTS */
|
||||
typedef struct MonFdset MonFdset;
|
||||
struct MonFdset {
|
||||
int64_t id;
|
||||
QLIST_HEAD(, MonFdsetFd) fds;
|
||||
QLIST_HEAD(, MonFdsetFd) dup_fds;
|
||||
QLIST_ENTRY(MonFdset) next;
|
||||
};
|
||||
|
||||
/* Protects mon_fdsets */
|
||||
static QemuMutex mon_fdsets_lock;
|
||||
static QLIST_HEAD(, MonFdset) mon_fdsets;
|
||||
|
||||
static HMPCommand hmp_info_cmds[];
|
||||
|
||||
char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
|
||||
@ -746,407 +714,6 @@ static void hmp_info_mtree(Monitor *mon, const QDict *qdict)
|
||||
mtree_info(flatview, dispatch_tree, owner, disabled);
|
||||
}
|
||||
|
||||
void qmp_getfd(const char *fdname, Error **errp)
|
||||
{
|
||||
Monitor *cur_mon = monitor_cur();
|
||||
mon_fd_t *monfd;
|
||||
int fd, tmp_fd;
|
||||
|
||||
fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
|
||||
if (fd == -1) {
|
||||
error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
|
||||
return;
|
||||
}
|
||||
|
||||
if (qemu_isdigit(fdname[0])) {
|
||||
close(fd);
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
|
||||
"a name not starting with a digit");
|
||||
return;
|
||||
}
|
||||
|
||||
QEMU_LOCK_GUARD(&cur_mon->mon_lock);
|
||||
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
||||
if (strcmp(monfd->name, fdname) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp_fd = monfd->fd;
|
||||
monfd->fd = fd;
|
||||
/* Make sure close() is outside critical section */
|
||||
close(tmp_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
monfd = g_new0(mon_fd_t, 1);
|
||||
monfd->name = g_strdup(fdname);
|
||||
monfd->fd = fd;
|
||||
|
||||
QLIST_INSERT_HEAD(&cur_mon->fds, monfd, next);
|
||||
}
|
||||
|
||||
void qmp_closefd(const char *fdname, Error **errp)
|
||||
{
|
||||
Monitor *cur_mon = monitor_cur();
|
||||
mon_fd_t *monfd;
|
||||
int tmp_fd;
|
||||
|
||||
qemu_mutex_lock(&cur_mon->mon_lock);
|
||||
QLIST_FOREACH(monfd, &cur_mon->fds, next) {
|
||||
if (strcmp(monfd->name, fdname) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QLIST_REMOVE(monfd, next);
|
||||
tmp_fd = monfd->fd;
|
||||
g_free(monfd->name);
|
||||
g_free(monfd);
|
||||
qemu_mutex_unlock(&cur_mon->mon_lock);
|
||||
/* Make sure close() is outside critical section */
|
||||
close(tmp_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&cur_mon->mon_lock);
|
||||
error_setg(errp, "File descriptor named '%s' not found", fdname);
|
||||
}
|
||||
|
||||
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
|
||||
{
|
||||
mon_fd_t *monfd;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon->mon_lock);
|
||||
QLIST_FOREACH(monfd, &mon->fds, next) {
|
||||
int fd;
|
||||
|
||||
if (strcmp(monfd->name, fdname) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = monfd->fd;
|
||||
assert(fd >= 0);
|
||||
|
||||
/* caller takes ownership of fd */
|
||||
QLIST_REMOVE(monfd, next);
|
||||
g_free(monfd->name);
|
||||
g_free(monfd);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
error_setg(errp, "File descriptor named '%s' has not been found", fdname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void monitor_fdset_cleanup(MonFdset *mon_fdset)
|
||||
{
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
MonFdsetFd *mon_fdset_fd_next;
|
||||
|
||||
QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) {
|
||||
if ((mon_fdset_fd->removed ||
|
||||
(QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) &&
|
||||
runstate_is_running()) {
|
||||
close(mon_fdset_fd->fd);
|
||||
g_free(mon_fdset_fd->opaque);
|
||||
QLIST_REMOVE(mon_fdset_fd, next);
|
||||
g_free(mon_fdset_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
||||
QLIST_REMOVE(mon_fdset, next);
|
||||
g_free(mon_fdset);
|
||||
}
|
||||
}
|
||||
|
||||
void monitor_fdsets_cleanup(void)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdset *mon_fdset_next;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
|
||||
monitor_fdset_cleanup(mon_fdset);
|
||||
}
|
||||
}
|
||||
|
||||
AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id,
|
||||
const char *opaque, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
Monitor *mon = monitor_cur();
|
||||
AddfdInfo *fdinfo;
|
||||
|
||||
fd = qemu_chr_fe_get_msgfd(&mon->chr);
|
||||
if (fd == -1) {
|
||||
error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
|
||||
goto error;
|
||||
}
|
||||
|
||||
fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp);
|
||||
if (fdinfo) {
|
||||
return fdinfo;
|
||||
}
|
||||
|
||||
error:
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
char fd_str[60];
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
if (mon_fdset->id != fdset_id) {
|
||||
continue;
|
||||
}
|
||||
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
||||
if (has_fd) {
|
||||
if (mon_fdset_fd->fd != fd) {
|
||||
continue;
|
||||
}
|
||||
mon_fdset_fd->removed = true;
|
||||
break;
|
||||
} else {
|
||||
mon_fdset_fd->removed = true;
|
||||
}
|
||||
}
|
||||
if (has_fd && !mon_fdset_fd) {
|
||||
goto error;
|
||||
}
|
||||
monitor_fdset_cleanup(mon_fdset);
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
if (has_fd) {
|
||||
snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
|
||||
fdset_id, fd);
|
||||
} else {
|
||||
snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
|
||||
}
|
||||
error_setg(errp, "File descriptor named '%s' not found", fd_str);
|
||||
}
|
||||
|
||||
FdsetInfoList *qmp_query_fdsets(Error **errp)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
FdsetInfoList *fdset_list = NULL;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info));
|
||||
|
||||
fdset_info->fdset_id = mon_fdset->id;
|
||||
|
||||
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
||||
FdsetFdInfo *fdsetfd_info;
|
||||
|
||||
fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
|
||||
fdsetfd_info->fd = mon_fdset_fd->fd;
|
||||
fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque);
|
||||
|
||||
QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info);
|
||||
}
|
||||
|
||||
QAPI_LIST_PREPEND(fdset_list, fdset_info);
|
||||
}
|
||||
|
||||
return fdset_list;
|
||||
}
|
||||
|
||||
AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
|
||||
const char *opaque, Error **errp)
|
||||
{
|
||||
MonFdset *mon_fdset = NULL;
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
AddfdInfo *fdinfo;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
if (has_fdset_id) {
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
/* Break if match found or match impossible due to ordering by ID */
|
||||
if (fdset_id <= mon_fdset->id) {
|
||||
if (fdset_id < mon_fdset->id) {
|
||||
mon_fdset = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mon_fdset == NULL) {
|
||||
int64_t fdset_id_prev = -1;
|
||||
MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
|
||||
|
||||
if (has_fdset_id) {
|
||||
if (fdset_id < 0) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
|
||||
"a non-negative value");
|
||||
return NULL;
|
||||
}
|
||||
/* Use specified fdset ID */
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
mon_fdset_cur = mon_fdset;
|
||||
if (fdset_id < mon_fdset_cur->id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Use first available fdset ID */
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
mon_fdset_cur = mon_fdset;
|
||||
if (fdset_id_prev == mon_fdset_cur->id - 1) {
|
||||
fdset_id_prev = mon_fdset_cur->id;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mon_fdset = g_malloc0(sizeof(*mon_fdset));
|
||||
if (has_fdset_id) {
|
||||
mon_fdset->id = fdset_id;
|
||||
} else {
|
||||
mon_fdset->id = fdset_id_prev + 1;
|
||||
}
|
||||
|
||||
/* The fdset list is ordered by fdset ID */
|
||||
if (!mon_fdset_cur) {
|
||||
QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
|
||||
} else if (mon_fdset->id < mon_fdset_cur->id) {
|
||||
QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
|
||||
} else {
|
||||
QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
|
||||
}
|
||||
}
|
||||
|
||||
mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
|
||||
mon_fdset_fd->fd = fd;
|
||||
mon_fdset_fd->removed = false;
|
||||
mon_fdset_fd->opaque = g_strdup(opaque);
|
||||
QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
|
||||
|
||||
fdinfo = g_malloc0(sizeof(*fdinfo));
|
||||
fdinfo->fdset_id = mon_fdset->id;
|
||||
fdinfo->fd = mon_fdset_fd->fd;
|
||||
|
||||
return fdinfo;
|
||||
}
|
||||
|
||||
int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return -ENOENT;
|
||||
#else
|
||||
MonFdset *mon_fdset;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
MonFdsetFd *mon_fdset_fd;
|
||||
MonFdsetFd *mon_fdset_fd_dup;
|
||||
int fd = -1;
|
||||
int dup_fd;
|
||||
int mon_fd_flags;
|
||||
|
||||
if (mon_fdset->id != fdset_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
|
||||
mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
|
||||
if (mon_fd_flags == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
|
||||
fd = mon_fdset_fd->fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dup_fd = qemu_dup_flags(fd, flags);
|
||||
if (dup_fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
|
||||
mon_fdset_fd_dup->fd = dup_fd;
|
||||
QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
|
||||
return dup_fd;
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
|
||||
{
|
||||
MonFdset *mon_fdset;
|
||||
MonFdsetFd *mon_fdset_fd_dup;
|
||||
|
||||
QEMU_LOCK_GUARD(&mon_fdsets_lock);
|
||||
QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
|
||||
QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
|
||||
if (mon_fdset_fd_dup->fd == dup_fd) {
|
||||
if (remove) {
|
||||
QLIST_REMOVE(mon_fdset_fd_dup, next);
|
||||
g_free(mon_fdset_fd_dup);
|
||||
if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
|
||||
monitor_fdset_cleanup(mon_fdset);
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
return mon_fdset->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t monitor_fdset_dup_fd_find(int dup_fd)
|
||||
{
|
||||
return monitor_fdset_dup_fd_find_remove(dup_fd, false);
|
||||
}
|
||||
|
||||
void monitor_fdset_dup_fd_remove(int dup_fd)
|
||||
{
|
||||
monitor_fdset_dup_fd_find_remove(dup_fd, true);
|
||||
}
|
||||
|
||||
int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!qemu_isdigit(fdname[0]) && mon) {
|
||||
fd = monitor_get_fd(mon, fdname, errp);
|
||||
} else {
|
||||
fd = qemu_parse_fd(fdname);
|
||||
if (fd < 0) {
|
||||
error_setg(errp, "Invalid file descriptor number '%s'",
|
||||
fdname);
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Please update hmp-commands.hx when adding or changing commands */
|
||||
static HMPCommand hmp_info_cmds[] = {
|
||||
#include "hmp-commands-info.h"
|
||||
@ -1260,5 +827,4 @@ void monitor_init_globals(void)
|
||||
monitor_init_globals_core();
|
||||
monitor_init_qmp_commands();
|
||||
sortcmdlist();
|
||||
qemu_mutex_init(&mon_fdsets_lock);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user