2 * QEMU monitor file descriptor passing
4 * Copyright (c) 2003-2004 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "qemu/osdep.h"
26 #include "monitor-internal.h"
27 #include "qapi/error.h"
28 #include "qapi/qapi-commands-misc.h"
29 #include "qapi/qmp/qerror.h"
30 #include "qemu/ctype.h"
31 #include "qemu/cutils.h"
32 #include "sysemu/runstate.h"
34 /* file descriptors passed via SCM_RIGHTS */
35 typedef struct mon_fd_t mon_fd_t
;
39 QLIST_ENTRY(mon_fd_t
) next
;
42 /* file descriptor associated with a file descriptor set */
43 typedef struct MonFdsetFd MonFdsetFd
;
47 QLIST_ENTRY(MonFdsetFd
) next
;
50 /* file descriptor set containing fds passed via SCM_RIGHTS */
51 typedef struct MonFdset MonFdset
;
54 QLIST_HEAD(, MonFdsetFd
) fds
;
55 QLIST_HEAD(, MonFdsetFd
) dup_fds
;
56 QLIST_ENTRY(MonFdset
) next
;
59 /* Protects mon_fdsets */
60 static QemuMutex mon_fdsets_lock
;
61 static QLIST_HEAD(, MonFdset
) mon_fdsets
;
63 static bool monitor_add_fd(Monitor
*mon
, int fd
, const char *fdname
, Error
**errp
)
67 if (qemu_isdigit(fdname
[0])) {
69 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, "fdname",
70 "a name not starting with a digit");
74 /* See close() call below. */
75 qemu_mutex_lock(&mon
->mon_lock
);
76 QLIST_FOREACH(monfd
, &mon
->fds
, next
) {
79 if (strcmp(monfd
->name
, fdname
) != 0) {
85 qemu_mutex_unlock(&mon
->mon_lock
);
86 /* Make sure close() is outside critical section */
91 monfd
= g_new0(mon_fd_t
, 1);
92 monfd
->name
= g_strdup(fdname
);
95 QLIST_INSERT_HEAD(&mon
->fds
, monfd
, next
);
96 qemu_mutex_unlock(&mon
->mon_lock
);
101 void qmp_getfd(const char *fdname
, Error
**errp
)
103 Monitor
*cur_mon
= monitor_cur();
106 fd
= qemu_chr_fe_get_msgfd(&cur_mon
->chr
);
108 error_setg(errp
, "No file descriptor supplied via SCM_RIGHTS");
112 monitor_add_fd(cur_mon
, fd
, fdname
, errp
);
116 void qmp_closefd(const char *fdname
, Error
**errp
)
118 Monitor
*cur_mon
= monitor_cur();
122 qemu_mutex_lock(&cur_mon
->mon_lock
);
123 QLIST_FOREACH(monfd
, &cur_mon
->fds
, next
) {
124 if (strcmp(monfd
->name
, fdname
) != 0) {
128 QLIST_REMOVE(monfd
, next
);
132 qemu_mutex_unlock(&cur_mon
->mon_lock
);
133 /* Make sure close() is outside critical section */
138 qemu_mutex_unlock(&cur_mon
->mon_lock
);
139 error_setg(errp
, "File descriptor named '%s' not found", fdname
);
142 int monitor_get_fd(Monitor
*mon
, const char *fdname
, Error
**errp
)
146 QEMU_LOCK_GUARD(&mon
->mon_lock
);
147 QLIST_FOREACH(monfd
, &mon
->fds
, next
) {
150 if (strcmp(monfd
->name
, fdname
) != 0) {
157 /* caller takes ownership of fd */
158 QLIST_REMOVE(monfd
, next
);
165 error_setg(errp
, "File descriptor named '%s' has not been found", fdname
);
169 static void monitor_fdset_free(MonFdset
*mon_fdset
)
171 QLIST_REMOVE(mon_fdset
, next
);
175 static void monitor_fdset_free_if_empty(MonFdset
*mon_fdset
)
178 * Only remove an empty fdset. The fds are owned by the user and
179 * should have been removed with qmp_remove_fd(). The dup_fds are
180 * owned by QEMU and should have been removed with qemu_close().
182 if (QLIST_EMPTY(&mon_fdset
->fds
) && QLIST_EMPTY(&mon_fdset
->dup_fds
)) {
183 monitor_fdset_free(mon_fdset
);
187 static void monitor_fdset_fd_free(MonFdsetFd
*mon_fdset_fd
)
189 close(mon_fdset_fd
->fd
);
190 g_free(mon_fdset_fd
->opaque
);
191 QLIST_REMOVE(mon_fdset_fd
, next
);
192 g_free(mon_fdset_fd
);
195 void monitor_fdsets_cleanup(void)
198 MonFdset
*mon_fdset_next
;
200 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
201 QLIST_FOREACH_SAFE(mon_fdset
, &mon_fdsets
, next
, mon_fdset_next
) {
202 monitor_fdset_free_if_empty(mon_fdset
);
206 AddfdInfo
*qmp_add_fd(bool has_fdset_id
, int64_t fdset_id
,
207 const char *opaque
, Error
**errp
)
210 Monitor
*mon
= monitor_cur();
213 fd
= qemu_chr_fe_get_msgfd(&mon
->chr
);
215 error_setg(errp
, "No file descriptor supplied via SCM_RIGHTS");
219 fdinfo
= monitor_fdset_add_fd(fd
, has_fdset_id
, fdset_id
, opaque
, errp
);
232 void qmp_get_win32_socket(const char *infos
, const char *fdname
, Error
**errp
)
234 g_autofree WSAPROTOCOL_INFOW
*info
= NULL
;
239 info
= (void *)g_base64_decode(infos
, &len
);
240 if (len
!= sizeof(*info
)) {
241 error_setg(errp
, "Invalid WSAPROTOCOL_INFOW value");
245 sk
= WSASocketW(FROM_PROTOCOL_INFO
,
249 if (sk
== INVALID_SOCKET
) {
250 error_setg_win32(errp
, WSAGetLastError(), "Couldn't import socket");
254 fd
= _open_osfhandle(sk
, _O_BINARY
);
256 error_setg_errno(errp
, errno
, "Failed to associate a FD with the SOCKET");
261 monitor_add_fd(monitor_cur(), fd
, fdname
, errp
);
266 void qmp_remove_fd(int64_t fdset_id
, bool has_fd
, int64_t fd
, Error
**errp
)
269 MonFdsetFd
*mon_fdset_fd
, *mon_fdset_fd_next
;
272 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
273 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
274 if (mon_fdset
->id
!= fdset_id
) {
277 QLIST_FOREACH_SAFE(mon_fdset_fd
, &mon_fdset
->fds
, next
,
280 if (mon_fdset_fd
->fd
!= fd
) {
283 monitor_fdset_fd_free(mon_fdset_fd
);
286 monitor_fdset_fd_free(mon_fdset_fd
);
289 if (has_fd
&& !mon_fdset_fd
) {
292 monitor_fdset_free_if_empty(mon_fdset
);
298 snprintf(fd_str
, sizeof(fd_str
), "fdset-id:%" PRId64
", fd:%" PRId64
,
301 snprintf(fd_str
, sizeof(fd_str
), "fdset-id:%" PRId64
, fdset_id
);
303 error_setg(errp
, "File descriptor named '%s' not found", fd_str
);
306 FdsetInfoList
*qmp_query_fdsets(Error
**errp
)
309 MonFdsetFd
*mon_fdset_fd
;
310 FdsetInfoList
*fdset_list
= NULL
;
312 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
313 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
314 FdsetInfo
*fdset_info
= g_malloc0(sizeof(*fdset_info
));
316 fdset_info
->fdset_id
= mon_fdset
->id
;
318 QLIST_FOREACH(mon_fdset_fd
, &mon_fdset
->fds
, next
) {
319 FdsetFdInfo
*fdsetfd_info
;
321 fdsetfd_info
= g_malloc0(sizeof(*fdsetfd_info
));
322 fdsetfd_info
->fd
= mon_fdset_fd
->fd
;
323 fdsetfd_info
->opaque
= g_strdup(mon_fdset_fd
->opaque
);
325 QAPI_LIST_PREPEND(fdset_info
->fds
, fdsetfd_info
);
328 QAPI_LIST_PREPEND(fdset_list
, fdset_info
);
334 AddfdInfo
*monitor_fdset_add_fd(int fd
, bool has_fdset_id
, int64_t fdset_id
,
335 const char *opaque
, Error
**errp
)
337 MonFdset
*mon_fdset
= NULL
;
338 MonFdsetFd
*mon_fdset_fd
;
341 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
343 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
344 /* Break if match found or match impossible due to ordering by ID */
345 if (fdset_id
<= mon_fdset
->id
) {
346 if (fdset_id
< mon_fdset
->id
) {
354 if (mon_fdset
== NULL
) {
355 int64_t fdset_id_prev
= -1;
356 MonFdset
*mon_fdset_cur
= QLIST_FIRST(&mon_fdsets
);
360 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, "fdset-id",
361 "a non-negative value");
364 /* Use specified fdset ID */
365 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
366 mon_fdset_cur
= mon_fdset
;
367 if (fdset_id
< mon_fdset_cur
->id
) {
372 /* Use first available fdset ID */
373 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
374 mon_fdset_cur
= mon_fdset
;
375 if (fdset_id_prev
== mon_fdset_cur
->id
- 1) {
376 fdset_id_prev
= mon_fdset_cur
->id
;
383 mon_fdset
= g_malloc0(sizeof(*mon_fdset
));
385 mon_fdset
->id
= fdset_id
;
387 mon_fdset
->id
= fdset_id_prev
+ 1;
390 /* The fdset list is ordered by fdset ID */
391 if (!mon_fdset_cur
) {
392 QLIST_INSERT_HEAD(&mon_fdsets
, mon_fdset
, next
);
393 } else if (mon_fdset
->id
< mon_fdset_cur
->id
) {
394 QLIST_INSERT_BEFORE(mon_fdset_cur
, mon_fdset
, next
);
396 QLIST_INSERT_AFTER(mon_fdset_cur
, mon_fdset
, next
);
400 mon_fdset_fd
= g_malloc0(sizeof(*mon_fdset_fd
));
401 mon_fdset_fd
->fd
= fd
;
402 mon_fdset_fd
->opaque
= g_strdup(opaque
);
403 QLIST_INSERT_HEAD(&mon_fdset
->fds
, mon_fdset_fd
, next
);
405 fdinfo
= g_malloc0(sizeof(*fdinfo
));
406 fdinfo
->fdset_id
= mon_fdset
->id
;
407 fdinfo
->fd
= mon_fdset_fd
->fd
;
412 int monitor_fdset_dup_fd_add(int64_t fdset_id
, int flags
, Error
**errp
)
415 error_setg(errp
, "Platform does not support fd passing (fdset)");
420 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
421 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
422 MonFdsetFd
*mon_fdset_fd
;
423 MonFdsetFd
*mon_fdset_fd_dup
;
427 int mask
= O_ACCMODE
;
433 if (mon_fdset
->id
!= fdset_id
) {
437 QLIST_FOREACH(mon_fdset_fd
, &mon_fdset
->fds
, next
) {
438 mon_fd_flags
= fcntl(mon_fdset_fd
->fd
, F_GETFL
);
439 if (mon_fd_flags
== -1) {
440 error_setg(errp
, "Failed to read file status flags for fd=%d",
445 if ((flags
& mask
) == (mon_fd_flags
& mask
)) {
446 fd
= mon_fdset_fd
->fd
;
454 "Failed to find file descriptor with matching flags=0x%x",
459 dup_fd
= qemu_dup_flags(fd
, flags
);
461 error_setg(errp
, "Failed to dup() given file descriptor fd=%d", fd
);
465 mon_fdset_fd_dup
= g_malloc0(sizeof(*mon_fdset_fd_dup
));
466 mon_fdset_fd_dup
->fd
= dup_fd
;
467 QLIST_INSERT_HEAD(&mon_fdset
->dup_fds
, mon_fdset_fd_dup
, next
);
471 error_setg(errp
, "Failed to find fdset /dev/fdset/%" PRId64
, fdset_id
);
477 void monitor_fdset_dup_fd_remove(int dup_fd
)
480 MonFdsetFd
*mon_fdset_fd_dup
;
482 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
483 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
484 QLIST_FOREACH(mon_fdset_fd_dup
, &mon_fdset
->dup_fds
, next
) {
485 if (mon_fdset_fd_dup
->fd
== dup_fd
) {
486 QLIST_REMOVE(mon_fdset_fd_dup
, next
);
487 g_free(mon_fdset_fd_dup
);
488 monitor_fdset_free_if_empty(mon_fdset
);
495 int monitor_fd_param(Monitor
*mon
, const char *fdname
, Error
**errp
)
499 if (!qemu_isdigit(fdname
[0]) && mon
) {
500 fd
= monitor_get_fd(mon
, fdname
, errp
);
502 fd
= qemu_parse_fd(fdname
);
504 error_setg(errp
, "Invalid file descriptor number '%s'",
512 static void __attribute__((__constructor__
)) monitor_fds_init(void)
514 qemu_mutex_init(&mon_fdsets_lock
);