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
;
48 QLIST_ENTRY(MonFdsetFd
) next
;
51 /* file descriptor set containing fds passed via SCM_RIGHTS */
52 typedef struct MonFdset MonFdset
;
55 QLIST_HEAD(, MonFdsetFd
) fds
;
56 QLIST_HEAD(, MonFdsetFd
) dup_fds
;
57 QLIST_ENTRY(MonFdset
) next
;
60 /* Protects mon_fdsets */
61 static QemuMutex mon_fdsets_lock
;
62 static QLIST_HEAD(, MonFdset
) mon_fdsets
;
64 static bool monitor_add_fd(Monitor
*mon
, int fd
, const char *fdname
, Error
**errp
)
68 if (qemu_isdigit(fdname
[0])) {
70 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, "fdname",
71 "a name not starting with a digit");
75 /* See close() call below. */
76 qemu_mutex_lock(&mon
->mon_lock
);
77 QLIST_FOREACH(monfd
, &mon
->fds
, next
) {
80 if (strcmp(monfd
->name
, fdname
) != 0) {
86 qemu_mutex_unlock(&mon
->mon_lock
);
87 /* Make sure close() is outside critical section */
92 monfd
= g_new0(mon_fd_t
, 1);
93 monfd
->name
= g_strdup(fdname
);
96 QLIST_INSERT_HEAD(&mon
->fds
, monfd
, next
);
97 qemu_mutex_unlock(&mon
->mon_lock
);
102 void qmp_getfd(const char *fdname
, Error
**errp
)
104 Monitor
*cur_mon
= monitor_cur();
107 fd
= qemu_chr_fe_get_msgfd(&cur_mon
->chr
);
109 error_setg(errp
, "No file descriptor supplied via SCM_RIGHTS");
113 monitor_add_fd(cur_mon
, fd
, fdname
, errp
);
117 void qmp_closefd(const char *fdname
, Error
**errp
)
119 Monitor
*cur_mon
= monitor_cur();
123 qemu_mutex_lock(&cur_mon
->mon_lock
);
124 QLIST_FOREACH(monfd
, &cur_mon
->fds
, next
) {
125 if (strcmp(monfd
->name
, fdname
) != 0) {
129 QLIST_REMOVE(monfd
, next
);
133 qemu_mutex_unlock(&cur_mon
->mon_lock
);
134 /* Make sure close() is outside critical section */
139 qemu_mutex_unlock(&cur_mon
->mon_lock
);
140 error_setg(errp
, "File descriptor named '%s' not found", fdname
);
143 int monitor_get_fd(Monitor
*mon
, const char *fdname
, Error
**errp
)
147 QEMU_LOCK_GUARD(&mon
->mon_lock
);
148 QLIST_FOREACH(monfd
, &mon
->fds
, next
) {
151 if (strcmp(monfd
->name
, fdname
) != 0) {
158 /* caller takes ownership of fd */
159 QLIST_REMOVE(monfd
, next
);
166 error_setg(errp
, "File descriptor named '%s' has not been found", fdname
);
170 static void monitor_fdset_cleanup(MonFdset
*mon_fdset
)
172 MonFdsetFd
*mon_fdset_fd
;
173 MonFdsetFd
*mon_fdset_fd_next
;
175 QLIST_FOREACH_SAFE(mon_fdset_fd
, &mon_fdset
->fds
, next
, mon_fdset_fd_next
) {
176 if ((mon_fdset_fd
->removed
||
177 (QLIST_EMPTY(&mon_fdset
->dup_fds
) && mon_refcount
== 0)) &&
178 runstate_is_running()) {
179 close(mon_fdset_fd
->fd
);
180 g_free(mon_fdset_fd
->opaque
);
181 QLIST_REMOVE(mon_fdset_fd
, next
);
182 g_free(mon_fdset_fd
);
186 if (QLIST_EMPTY(&mon_fdset
->fds
) && QLIST_EMPTY(&mon_fdset
->dup_fds
)) {
187 QLIST_REMOVE(mon_fdset
, next
);
192 void monitor_fdsets_cleanup(void)
195 MonFdset
*mon_fdset_next
;
197 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
198 QLIST_FOREACH_SAFE(mon_fdset
, &mon_fdsets
, next
, mon_fdset_next
) {
199 monitor_fdset_cleanup(mon_fdset
);
203 AddfdInfo
*qmp_add_fd(bool has_fdset_id
, int64_t fdset_id
,
204 const char *opaque
, Error
**errp
)
207 Monitor
*mon
= monitor_cur();
210 fd
= qemu_chr_fe_get_msgfd(&mon
->chr
);
212 error_setg(errp
, "No file descriptor supplied via SCM_RIGHTS");
216 fdinfo
= monitor_fdset_add_fd(fd
, has_fdset_id
, fdset_id
, opaque
, errp
);
229 void qmp_get_win32_socket(const char *infos
, const char *fdname
, Error
**errp
)
231 g_autofree WSAPROTOCOL_INFOW
*info
= NULL
;
236 info
= (void *)g_base64_decode(infos
, &len
);
237 if (len
!= sizeof(*info
)) {
238 error_setg(errp
, "Invalid WSAPROTOCOL_INFOW value");
242 sk
= WSASocketW(FROM_PROTOCOL_INFO
,
246 if (sk
== INVALID_SOCKET
) {
247 error_setg_win32(errp
, WSAGetLastError(), "Couldn't import socket");
251 fd
= _open_osfhandle(sk
, _O_BINARY
);
253 error_setg_errno(errp
, errno
, "Failed to associate a FD with the SOCKET");
258 monitor_add_fd(monitor_cur(), fd
, fdname
, errp
);
263 void qmp_remove_fd(int64_t fdset_id
, bool has_fd
, int64_t fd
, Error
**errp
)
266 MonFdsetFd
*mon_fdset_fd
;
269 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
270 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
271 if (mon_fdset
->id
!= fdset_id
) {
274 QLIST_FOREACH(mon_fdset_fd
, &mon_fdset
->fds
, next
) {
276 if (mon_fdset_fd
->fd
!= fd
) {
279 mon_fdset_fd
->removed
= true;
282 mon_fdset_fd
->removed
= true;
285 if (has_fd
&& !mon_fdset_fd
) {
288 monitor_fdset_cleanup(mon_fdset
);
294 snprintf(fd_str
, sizeof(fd_str
), "fdset-id:%" PRId64
", fd:%" PRId64
,
297 snprintf(fd_str
, sizeof(fd_str
), "fdset-id:%" PRId64
, fdset_id
);
299 error_setg(errp
, "File descriptor named '%s' not found", fd_str
);
302 FdsetInfoList
*qmp_query_fdsets(Error
**errp
)
305 MonFdsetFd
*mon_fdset_fd
;
306 FdsetInfoList
*fdset_list
= NULL
;
308 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
309 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
310 FdsetInfo
*fdset_info
= g_malloc0(sizeof(*fdset_info
));
312 fdset_info
->fdset_id
= mon_fdset
->id
;
314 QLIST_FOREACH(mon_fdset_fd
, &mon_fdset
->fds
, next
) {
315 FdsetFdInfo
*fdsetfd_info
;
317 fdsetfd_info
= g_malloc0(sizeof(*fdsetfd_info
));
318 fdsetfd_info
->fd
= mon_fdset_fd
->fd
;
319 fdsetfd_info
->opaque
= g_strdup(mon_fdset_fd
->opaque
);
321 QAPI_LIST_PREPEND(fdset_info
->fds
, fdsetfd_info
);
324 QAPI_LIST_PREPEND(fdset_list
, fdset_info
);
330 AddfdInfo
*monitor_fdset_add_fd(int fd
, bool has_fdset_id
, int64_t fdset_id
,
331 const char *opaque
, Error
**errp
)
333 MonFdset
*mon_fdset
= NULL
;
334 MonFdsetFd
*mon_fdset_fd
;
337 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
339 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
340 /* Break if match found or match impossible due to ordering by ID */
341 if (fdset_id
<= mon_fdset
->id
) {
342 if (fdset_id
< mon_fdset
->id
) {
350 if (mon_fdset
== NULL
) {
351 int64_t fdset_id_prev
= -1;
352 MonFdset
*mon_fdset_cur
= QLIST_FIRST(&mon_fdsets
);
356 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, "fdset-id",
357 "a non-negative value");
360 /* Use specified fdset ID */
361 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
362 mon_fdset_cur
= mon_fdset
;
363 if (fdset_id
< mon_fdset_cur
->id
) {
368 /* Use first available fdset ID */
369 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
370 mon_fdset_cur
= mon_fdset
;
371 if (fdset_id_prev
== mon_fdset_cur
->id
- 1) {
372 fdset_id_prev
= mon_fdset_cur
->id
;
379 mon_fdset
= g_malloc0(sizeof(*mon_fdset
));
381 mon_fdset
->id
= fdset_id
;
383 mon_fdset
->id
= fdset_id_prev
+ 1;
386 /* The fdset list is ordered by fdset ID */
387 if (!mon_fdset_cur
) {
388 QLIST_INSERT_HEAD(&mon_fdsets
, mon_fdset
, next
);
389 } else if (mon_fdset
->id
< mon_fdset_cur
->id
) {
390 QLIST_INSERT_BEFORE(mon_fdset_cur
, mon_fdset
, next
);
392 QLIST_INSERT_AFTER(mon_fdset_cur
, mon_fdset
, next
);
396 mon_fdset_fd
= g_malloc0(sizeof(*mon_fdset_fd
));
397 mon_fdset_fd
->fd
= fd
;
398 mon_fdset_fd
->removed
= false;
399 mon_fdset_fd
->opaque
= g_strdup(opaque
);
400 QLIST_INSERT_HEAD(&mon_fdset
->fds
, mon_fdset_fd
, next
);
402 fdinfo
= g_malloc0(sizeof(*fdinfo
));
403 fdinfo
->fdset_id
= mon_fdset
->id
;
404 fdinfo
->fd
= mon_fdset_fd
->fd
;
409 int monitor_fdset_dup_fd_add(int64_t fdset_id
, int flags
)
416 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
417 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
418 MonFdsetFd
*mon_fdset_fd
;
419 MonFdsetFd
*mon_fdset_fd_dup
;
424 if (mon_fdset
->id
!= fdset_id
) {
428 QLIST_FOREACH(mon_fdset_fd
, &mon_fdset
->fds
, next
) {
429 mon_fd_flags
= fcntl(mon_fdset_fd
->fd
, F_GETFL
);
430 if (mon_fd_flags
== -1) {
434 if ((flags
& O_ACCMODE
) == (mon_fd_flags
& O_ACCMODE
)) {
435 fd
= mon_fdset_fd
->fd
;
445 dup_fd
= qemu_dup_flags(fd
, flags
);
450 mon_fdset_fd_dup
= g_malloc0(sizeof(*mon_fdset_fd_dup
));
451 mon_fdset_fd_dup
->fd
= dup_fd
;
452 QLIST_INSERT_HEAD(&mon_fdset
->dup_fds
, mon_fdset_fd_dup
, next
);
461 static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd
, bool remove
)
464 MonFdsetFd
*mon_fdset_fd_dup
;
466 QEMU_LOCK_GUARD(&mon_fdsets_lock
);
467 QLIST_FOREACH(mon_fdset
, &mon_fdsets
, next
) {
468 QLIST_FOREACH(mon_fdset_fd_dup
, &mon_fdset
->dup_fds
, next
) {
469 if (mon_fdset_fd_dup
->fd
== dup_fd
) {
471 QLIST_REMOVE(mon_fdset_fd_dup
, next
);
472 g_free(mon_fdset_fd_dup
);
473 if (QLIST_EMPTY(&mon_fdset
->dup_fds
)) {
474 monitor_fdset_cleanup(mon_fdset
);
478 return mon_fdset
->id
;
487 int64_t monitor_fdset_dup_fd_find(int dup_fd
)
489 return monitor_fdset_dup_fd_find_remove(dup_fd
, false);
492 void monitor_fdset_dup_fd_remove(int dup_fd
)
494 monitor_fdset_dup_fd_find_remove(dup_fd
, true);
497 int monitor_fd_param(Monitor
*mon
, const char *fdname
, Error
**errp
)
501 if (!qemu_isdigit(fdname
[0]) && mon
) {
502 fd
= monitor_get_fd(mon
, fdname
, errp
);
504 fd
= qemu_parse_fd(fdname
);
506 error_setg(errp
, "Invalid file descriptor number '%s'",
514 static void __attribute__((__constructor__
)) monitor_fds_init(void)
516 qemu_mutex_init(&mon_fdsets_lock
);