xref: /qemu/monitor/fds.c (revision 4bf21c7f)
17ef88b53SMarkus Armbruster /*
27ef88b53SMarkus Armbruster  * QEMU monitor file descriptor passing
37ef88b53SMarkus Armbruster  *
47ef88b53SMarkus Armbruster  * Copyright (c) 2003-2004 Fabrice Bellard
57ef88b53SMarkus Armbruster  *
67ef88b53SMarkus Armbruster  * Permission is hereby granted, free of charge, to any person obtaining a copy
77ef88b53SMarkus Armbruster  * of this software and associated documentation files (the "Software"), to deal
87ef88b53SMarkus Armbruster  * in the Software without restriction, including without limitation the rights
97ef88b53SMarkus Armbruster  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
107ef88b53SMarkus Armbruster  * copies of the Software, and to permit persons to whom the Software is
117ef88b53SMarkus Armbruster  * furnished to do so, subject to the following conditions:
127ef88b53SMarkus Armbruster  *
137ef88b53SMarkus Armbruster  * The above copyright notice and this permission notice shall be included in
147ef88b53SMarkus Armbruster  * all copies or substantial portions of the Software.
157ef88b53SMarkus Armbruster  *
167ef88b53SMarkus Armbruster  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
177ef88b53SMarkus Armbruster  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187ef88b53SMarkus Armbruster  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
197ef88b53SMarkus Armbruster  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
207ef88b53SMarkus Armbruster  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
217ef88b53SMarkus Armbruster  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
227ef88b53SMarkus Armbruster  * THE SOFTWARE.
237ef88b53SMarkus Armbruster  */
247ef88b53SMarkus Armbruster 
257ef88b53SMarkus Armbruster #include "qemu/osdep.h"
267ef88b53SMarkus Armbruster #include "monitor-internal.h"
277ef88b53SMarkus Armbruster #include "qapi/error.h"
287ef88b53SMarkus Armbruster #include "qapi/qapi-commands-misc.h"
297ef88b53SMarkus Armbruster #include "qapi/qmp/qerror.h"
307ef88b53SMarkus Armbruster #include "qemu/ctype.h"
317ef88b53SMarkus Armbruster #include "qemu/cutils.h"
327ef88b53SMarkus Armbruster #include "sysemu/runstate.h"
337ef88b53SMarkus Armbruster 
347ef88b53SMarkus Armbruster /* file descriptors passed via SCM_RIGHTS */
357ef88b53SMarkus Armbruster typedef struct mon_fd_t mon_fd_t;
367ef88b53SMarkus Armbruster struct mon_fd_t {
377ef88b53SMarkus Armbruster     char *name;
387ef88b53SMarkus Armbruster     int fd;
397ef88b53SMarkus Armbruster     QLIST_ENTRY(mon_fd_t) next;
407ef88b53SMarkus Armbruster };
417ef88b53SMarkus Armbruster 
427ef88b53SMarkus Armbruster /* file descriptor associated with a file descriptor set */
437ef88b53SMarkus Armbruster typedef struct MonFdsetFd MonFdsetFd;
447ef88b53SMarkus Armbruster struct MonFdsetFd {
457ef88b53SMarkus Armbruster     int fd;
467ef88b53SMarkus Armbruster     bool removed;
477ef88b53SMarkus Armbruster     char *opaque;
487ef88b53SMarkus Armbruster     QLIST_ENTRY(MonFdsetFd) next;
497ef88b53SMarkus Armbruster };
507ef88b53SMarkus Armbruster 
517ef88b53SMarkus Armbruster /* file descriptor set containing fds passed via SCM_RIGHTS */
527ef88b53SMarkus Armbruster typedef struct MonFdset MonFdset;
537ef88b53SMarkus Armbruster struct MonFdset {
547ef88b53SMarkus Armbruster     int64_t id;
557ef88b53SMarkus Armbruster     QLIST_HEAD(, MonFdsetFd) fds;
567ef88b53SMarkus Armbruster     QLIST_HEAD(, MonFdsetFd) dup_fds;
577ef88b53SMarkus Armbruster     QLIST_ENTRY(MonFdset) next;
587ef88b53SMarkus Armbruster };
597ef88b53SMarkus Armbruster 
607ef88b53SMarkus Armbruster /* Protects mon_fdsets */
617ef88b53SMarkus Armbruster static QemuMutex mon_fdsets_lock;
627ef88b53SMarkus Armbruster static QLIST_HEAD(, MonFdset) mon_fdsets;
637ef88b53SMarkus Armbruster 
monitor_add_fd(Monitor * mon,int fd,const char * fdname,Error ** errp)644cda177cSMarc-André Lureau static bool monitor_add_fd(Monitor *mon, int fd, const char *fdname, Error **errp)
654cda177cSMarc-André Lureau {
664cda177cSMarc-André Lureau     mon_fd_t *monfd;
674cda177cSMarc-André Lureau 
684cda177cSMarc-André Lureau     if (qemu_isdigit(fdname[0])) {
694cda177cSMarc-André Lureau         close(fd);
704cda177cSMarc-André Lureau         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
714cda177cSMarc-André Lureau                    "a name not starting with a digit");
724cda177cSMarc-André Lureau         return false;
734cda177cSMarc-André Lureau     }
744cda177cSMarc-André Lureau 
754cda177cSMarc-André Lureau     /* See close() call below. */
764cda177cSMarc-André Lureau     qemu_mutex_lock(&mon->mon_lock);
774cda177cSMarc-André Lureau     QLIST_FOREACH(monfd, &mon->fds, next) {
784cda177cSMarc-André Lureau         int tmp_fd;
794cda177cSMarc-André Lureau 
804cda177cSMarc-André Lureau         if (strcmp(monfd->name, fdname) != 0) {
814cda177cSMarc-André Lureau             continue;
824cda177cSMarc-André Lureau         }
834cda177cSMarc-André Lureau 
844cda177cSMarc-André Lureau         tmp_fd = monfd->fd;
854cda177cSMarc-André Lureau         monfd->fd = fd;
864cda177cSMarc-André Lureau         qemu_mutex_unlock(&mon->mon_lock);
874cda177cSMarc-André Lureau         /* Make sure close() is outside critical section */
884cda177cSMarc-André Lureau         close(tmp_fd);
894cda177cSMarc-André Lureau         return true;
904cda177cSMarc-André Lureau     }
914cda177cSMarc-André Lureau 
924cda177cSMarc-André Lureau     monfd = g_new0(mon_fd_t, 1);
934cda177cSMarc-André Lureau     monfd->name = g_strdup(fdname);
944cda177cSMarc-André Lureau     monfd->fd = fd;
954cda177cSMarc-André Lureau 
964cda177cSMarc-André Lureau     QLIST_INSERT_HEAD(&mon->fds, monfd, next);
974cda177cSMarc-André Lureau     qemu_mutex_unlock(&mon->mon_lock);
984cda177cSMarc-André Lureau     return true;
994cda177cSMarc-André Lureau }
1004cda177cSMarc-André Lureau 
101*4bf21c7fSMarc-André Lureau #ifdef CONFIG_POSIX
qmp_getfd(const char * fdname,Error ** errp)1027ef88b53SMarkus Armbruster void qmp_getfd(const char *fdname, Error **errp)
1037ef88b53SMarkus Armbruster {
1047ef88b53SMarkus Armbruster     Monitor *cur_mon = monitor_cur();
1054cda177cSMarc-André Lureau     int fd;
1067ef88b53SMarkus Armbruster 
1077ef88b53SMarkus Armbruster     fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
1087ef88b53SMarkus Armbruster     if (fd == -1) {
1097ef88b53SMarkus Armbruster         error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
1107ef88b53SMarkus Armbruster         return;
1117ef88b53SMarkus Armbruster     }
1127ef88b53SMarkus Armbruster 
1134cda177cSMarc-André Lureau     monitor_add_fd(cur_mon, fd, fdname, errp);
1147ef88b53SMarkus Armbruster }
115*4bf21c7fSMarc-André Lureau #endif
1167ef88b53SMarkus Armbruster 
qmp_closefd(const char * fdname,Error ** errp)1177ef88b53SMarkus Armbruster void qmp_closefd(const char *fdname, Error **errp)
1187ef88b53SMarkus Armbruster {
1197ef88b53SMarkus Armbruster     Monitor *cur_mon = monitor_cur();
1207ef88b53SMarkus Armbruster     mon_fd_t *monfd;
1217ef88b53SMarkus Armbruster     int tmp_fd;
1227ef88b53SMarkus Armbruster 
1237ef88b53SMarkus Armbruster     qemu_mutex_lock(&cur_mon->mon_lock);
1247ef88b53SMarkus Armbruster     QLIST_FOREACH(monfd, &cur_mon->fds, next) {
1257ef88b53SMarkus Armbruster         if (strcmp(monfd->name, fdname) != 0) {
1267ef88b53SMarkus Armbruster             continue;
1277ef88b53SMarkus Armbruster         }
1287ef88b53SMarkus Armbruster 
1297ef88b53SMarkus Armbruster         QLIST_REMOVE(monfd, next);
1307ef88b53SMarkus Armbruster         tmp_fd = monfd->fd;
1317ef88b53SMarkus Armbruster         g_free(monfd->name);
1327ef88b53SMarkus Armbruster         g_free(monfd);
1337ef88b53SMarkus Armbruster         qemu_mutex_unlock(&cur_mon->mon_lock);
1347ef88b53SMarkus Armbruster         /* Make sure close() is outside critical section */
1357ef88b53SMarkus Armbruster         close(tmp_fd);
1367ef88b53SMarkus Armbruster         return;
1377ef88b53SMarkus Armbruster     }
1387ef88b53SMarkus Armbruster 
1397ef88b53SMarkus Armbruster     qemu_mutex_unlock(&cur_mon->mon_lock);
1407ef88b53SMarkus Armbruster     error_setg(errp, "File descriptor named '%s' not found", fdname);
1417ef88b53SMarkus Armbruster }
1427ef88b53SMarkus Armbruster 
monitor_get_fd(Monitor * mon,const char * fdname,Error ** errp)1437ef88b53SMarkus Armbruster int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
1447ef88b53SMarkus Armbruster {
1457ef88b53SMarkus Armbruster     mon_fd_t *monfd;
1467ef88b53SMarkus Armbruster 
1477ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon->mon_lock);
1487ef88b53SMarkus Armbruster     QLIST_FOREACH(monfd, &mon->fds, next) {
1497ef88b53SMarkus Armbruster         int fd;
1507ef88b53SMarkus Armbruster 
1517ef88b53SMarkus Armbruster         if (strcmp(monfd->name, fdname) != 0) {
1527ef88b53SMarkus Armbruster             continue;
1537ef88b53SMarkus Armbruster         }
1547ef88b53SMarkus Armbruster 
1557ef88b53SMarkus Armbruster         fd = monfd->fd;
1567ef88b53SMarkus Armbruster         assert(fd >= 0);
1577ef88b53SMarkus Armbruster 
1587ef88b53SMarkus Armbruster         /* caller takes ownership of fd */
1597ef88b53SMarkus Armbruster         QLIST_REMOVE(monfd, next);
1607ef88b53SMarkus Armbruster         g_free(monfd->name);
1617ef88b53SMarkus Armbruster         g_free(monfd);
1627ef88b53SMarkus Armbruster 
1637ef88b53SMarkus Armbruster         return fd;
1647ef88b53SMarkus Armbruster     }
1657ef88b53SMarkus Armbruster 
1667ef88b53SMarkus Armbruster     error_setg(errp, "File descriptor named '%s' has not been found", fdname);
1677ef88b53SMarkus Armbruster     return -1;
1687ef88b53SMarkus Armbruster }
1697ef88b53SMarkus Armbruster 
monitor_fdset_cleanup(MonFdset * mon_fdset)1707ef88b53SMarkus Armbruster static void monitor_fdset_cleanup(MonFdset *mon_fdset)
1717ef88b53SMarkus Armbruster {
1727ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd;
1737ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd_next;
1747ef88b53SMarkus Armbruster 
1757ef88b53SMarkus Armbruster     QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) {
1767ef88b53SMarkus Armbruster         if ((mon_fdset_fd->removed ||
1777ef88b53SMarkus Armbruster                 (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) &&
1787ef88b53SMarkus Armbruster                 runstate_is_running()) {
1797ef88b53SMarkus Armbruster             close(mon_fdset_fd->fd);
1807ef88b53SMarkus Armbruster             g_free(mon_fdset_fd->opaque);
1817ef88b53SMarkus Armbruster             QLIST_REMOVE(mon_fdset_fd, next);
1827ef88b53SMarkus Armbruster             g_free(mon_fdset_fd);
1837ef88b53SMarkus Armbruster         }
1847ef88b53SMarkus Armbruster     }
1857ef88b53SMarkus Armbruster 
1867ef88b53SMarkus Armbruster     if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
1877ef88b53SMarkus Armbruster         QLIST_REMOVE(mon_fdset, next);
1887ef88b53SMarkus Armbruster         g_free(mon_fdset);
1897ef88b53SMarkus Armbruster     }
1907ef88b53SMarkus Armbruster }
1917ef88b53SMarkus Armbruster 
monitor_fdsets_cleanup(void)1927ef88b53SMarkus Armbruster void monitor_fdsets_cleanup(void)
1937ef88b53SMarkus Armbruster {
1947ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
1957ef88b53SMarkus Armbruster     MonFdset *mon_fdset_next;
1967ef88b53SMarkus Armbruster 
1977ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
1987ef88b53SMarkus Armbruster     QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
1997ef88b53SMarkus Armbruster         monitor_fdset_cleanup(mon_fdset);
2007ef88b53SMarkus Armbruster     }
2017ef88b53SMarkus Armbruster }
2027ef88b53SMarkus Armbruster 
qmp_add_fd(bool has_fdset_id,int64_t fdset_id,const char * opaque,Error ** errp)2037ef88b53SMarkus Armbruster AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id,
2047ef88b53SMarkus Armbruster                       const char *opaque, Error **errp)
2057ef88b53SMarkus Armbruster {
2067ef88b53SMarkus Armbruster     int fd;
2077ef88b53SMarkus Armbruster     Monitor *mon = monitor_cur();
2087ef88b53SMarkus Armbruster     AddfdInfo *fdinfo;
2097ef88b53SMarkus Armbruster 
2107ef88b53SMarkus Armbruster     fd = qemu_chr_fe_get_msgfd(&mon->chr);
2117ef88b53SMarkus Armbruster     if (fd == -1) {
2127ef88b53SMarkus Armbruster         error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
2137ef88b53SMarkus Armbruster         goto error;
2147ef88b53SMarkus Armbruster     }
2157ef88b53SMarkus Armbruster 
2167ef88b53SMarkus Armbruster     fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp);
2177ef88b53SMarkus Armbruster     if (fdinfo) {
2187ef88b53SMarkus Armbruster         return fdinfo;
2197ef88b53SMarkus Armbruster     }
2207ef88b53SMarkus Armbruster 
2217ef88b53SMarkus Armbruster error:
2227ef88b53SMarkus Armbruster     if (fd != -1) {
2237ef88b53SMarkus Armbruster         close(fd);
2247ef88b53SMarkus Armbruster     }
2257ef88b53SMarkus Armbruster     return NULL;
2267ef88b53SMarkus Armbruster }
2277ef88b53SMarkus Armbruster 
2284cda177cSMarc-André Lureau #ifdef WIN32
qmp_get_win32_socket(const char * infos,const char * fdname,Error ** errp)2294cda177cSMarc-André Lureau void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp)
2304cda177cSMarc-André Lureau {
2314cda177cSMarc-André Lureau     g_autofree WSAPROTOCOL_INFOW *info = NULL;
2324cda177cSMarc-André Lureau     gsize len;
2334cda177cSMarc-André Lureau     SOCKET sk;
2344cda177cSMarc-André Lureau     int fd;
2354cda177cSMarc-André Lureau 
2364cda177cSMarc-André Lureau     info = (void *)g_base64_decode(infos, &len);
2374cda177cSMarc-André Lureau     if (len != sizeof(*info)) {
2384cda177cSMarc-André Lureau         error_setg(errp, "Invalid WSAPROTOCOL_INFOW value");
2394cda177cSMarc-André Lureau         return;
2404cda177cSMarc-André Lureau     }
2414cda177cSMarc-André Lureau 
2424cda177cSMarc-André Lureau     sk = WSASocketW(FROM_PROTOCOL_INFO,
2434cda177cSMarc-André Lureau                     FROM_PROTOCOL_INFO,
2444cda177cSMarc-André Lureau                     FROM_PROTOCOL_INFO,
2454cda177cSMarc-André Lureau                     info, 0, 0);
2464cda177cSMarc-André Lureau     if (sk == INVALID_SOCKET) {
2474cda177cSMarc-André Lureau         error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket");
2484cda177cSMarc-André Lureau         return;
2494cda177cSMarc-André Lureau     }
2504cda177cSMarc-André Lureau 
2514cda177cSMarc-André Lureau     fd = _open_osfhandle(sk, _O_BINARY);
2524cda177cSMarc-André Lureau     if (fd < 0) {
2534cda177cSMarc-André Lureau         error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET");
2544cda177cSMarc-André Lureau         closesocket(sk);
2554cda177cSMarc-André Lureau         return;
2564cda177cSMarc-André Lureau     }
2574cda177cSMarc-André Lureau 
2584cda177cSMarc-André Lureau     monitor_add_fd(monitor_cur(), fd, fdname, errp);
2594cda177cSMarc-André Lureau }
2604cda177cSMarc-André Lureau #endif
2614cda177cSMarc-André Lureau 
2624cda177cSMarc-André Lureau 
qmp_remove_fd(int64_t fdset_id,bool has_fd,int64_t fd,Error ** errp)2637ef88b53SMarkus Armbruster void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
2647ef88b53SMarkus Armbruster {
2657ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
2667ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd;
2677ef88b53SMarkus Armbruster     char fd_str[60];
2687ef88b53SMarkus Armbruster 
2697ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
2707ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
2717ef88b53SMarkus Armbruster         if (mon_fdset->id != fdset_id) {
2727ef88b53SMarkus Armbruster             continue;
2737ef88b53SMarkus Armbruster         }
2747ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
2757ef88b53SMarkus Armbruster             if (has_fd) {
2767ef88b53SMarkus Armbruster                 if (mon_fdset_fd->fd != fd) {
2777ef88b53SMarkus Armbruster                     continue;
2787ef88b53SMarkus Armbruster                 }
2797ef88b53SMarkus Armbruster                 mon_fdset_fd->removed = true;
2807ef88b53SMarkus Armbruster                 break;
2817ef88b53SMarkus Armbruster             } else {
2827ef88b53SMarkus Armbruster                 mon_fdset_fd->removed = true;
2837ef88b53SMarkus Armbruster             }
2847ef88b53SMarkus Armbruster         }
2857ef88b53SMarkus Armbruster         if (has_fd && !mon_fdset_fd) {
2867ef88b53SMarkus Armbruster             goto error;
2877ef88b53SMarkus Armbruster         }
2887ef88b53SMarkus Armbruster         monitor_fdset_cleanup(mon_fdset);
2897ef88b53SMarkus Armbruster         return;
2907ef88b53SMarkus Armbruster     }
2917ef88b53SMarkus Armbruster 
2927ef88b53SMarkus Armbruster error:
2937ef88b53SMarkus Armbruster     if (has_fd) {
2947ef88b53SMarkus Armbruster         snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
2957ef88b53SMarkus Armbruster                  fdset_id, fd);
2967ef88b53SMarkus Armbruster     } else {
2977ef88b53SMarkus Armbruster         snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
2987ef88b53SMarkus Armbruster     }
2997ef88b53SMarkus Armbruster     error_setg(errp, "File descriptor named '%s' not found", fd_str);
3007ef88b53SMarkus Armbruster }
3017ef88b53SMarkus Armbruster 
qmp_query_fdsets(Error ** errp)3027ef88b53SMarkus Armbruster FdsetInfoList *qmp_query_fdsets(Error **errp)
3037ef88b53SMarkus Armbruster {
3047ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
3057ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd;
3067ef88b53SMarkus Armbruster     FdsetInfoList *fdset_list = NULL;
3077ef88b53SMarkus Armbruster 
3087ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
3097ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3107ef88b53SMarkus Armbruster         FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info));
3117ef88b53SMarkus Armbruster 
3127ef88b53SMarkus Armbruster         fdset_info->fdset_id = mon_fdset->id;
3137ef88b53SMarkus Armbruster 
3147ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
3157ef88b53SMarkus Armbruster             FdsetFdInfo *fdsetfd_info;
3167ef88b53SMarkus Armbruster 
3177ef88b53SMarkus Armbruster             fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
3187ef88b53SMarkus Armbruster             fdsetfd_info->fd = mon_fdset_fd->fd;
3197ef88b53SMarkus Armbruster             fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque);
3207ef88b53SMarkus Armbruster 
3217ef88b53SMarkus Armbruster             QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info);
3227ef88b53SMarkus Armbruster         }
3237ef88b53SMarkus Armbruster 
3247ef88b53SMarkus Armbruster         QAPI_LIST_PREPEND(fdset_list, fdset_info);
3257ef88b53SMarkus Armbruster     }
3267ef88b53SMarkus Armbruster 
3277ef88b53SMarkus Armbruster     return fdset_list;
3287ef88b53SMarkus Armbruster }
3297ef88b53SMarkus Armbruster 
monitor_fdset_add_fd(int fd,bool has_fdset_id,int64_t fdset_id,const char * opaque,Error ** errp)3307ef88b53SMarkus Armbruster AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
3317ef88b53SMarkus Armbruster                                 const char *opaque, Error **errp)
3327ef88b53SMarkus Armbruster {
3337ef88b53SMarkus Armbruster     MonFdset *mon_fdset = NULL;
3347ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd;
3357ef88b53SMarkus Armbruster     AddfdInfo *fdinfo;
3367ef88b53SMarkus Armbruster 
3377ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
3387ef88b53SMarkus Armbruster     if (has_fdset_id) {
3397ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3407ef88b53SMarkus Armbruster             /* Break if match found or match impossible due to ordering by ID */
3417ef88b53SMarkus Armbruster             if (fdset_id <= mon_fdset->id) {
3427ef88b53SMarkus Armbruster                 if (fdset_id < mon_fdset->id) {
3437ef88b53SMarkus Armbruster                     mon_fdset = NULL;
3447ef88b53SMarkus Armbruster                 }
3457ef88b53SMarkus Armbruster                 break;
3467ef88b53SMarkus Armbruster             }
3477ef88b53SMarkus Armbruster         }
3487ef88b53SMarkus Armbruster     }
3497ef88b53SMarkus Armbruster 
3507ef88b53SMarkus Armbruster     if (mon_fdset == NULL) {
3517ef88b53SMarkus Armbruster         int64_t fdset_id_prev = -1;
3527ef88b53SMarkus Armbruster         MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
3537ef88b53SMarkus Armbruster 
3547ef88b53SMarkus Armbruster         if (has_fdset_id) {
3557ef88b53SMarkus Armbruster             if (fdset_id < 0) {
3567ef88b53SMarkus Armbruster                 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
3577ef88b53SMarkus Armbruster                            "a non-negative value");
3587ef88b53SMarkus Armbruster                 return NULL;
3597ef88b53SMarkus Armbruster             }
3607ef88b53SMarkus Armbruster             /* Use specified fdset ID */
3617ef88b53SMarkus Armbruster             QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3627ef88b53SMarkus Armbruster                 mon_fdset_cur = mon_fdset;
3637ef88b53SMarkus Armbruster                 if (fdset_id < mon_fdset_cur->id) {
3647ef88b53SMarkus Armbruster                     break;
3657ef88b53SMarkus Armbruster                 }
3667ef88b53SMarkus Armbruster             }
3677ef88b53SMarkus Armbruster         } else {
3687ef88b53SMarkus Armbruster             /* Use first available fdset ID */
3697ef88b53SMarkus Armbruster             QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3707ef88b53SMarkus Armbruster                 mon_fdset_cur = mon_fdset;
3717ef88b53SMarkus Armbruster                 if (fdset_id_prev == mon_fdset_cur->id - 1) {
3727ef88b53SMarkus Armbruster                     fdset_id_prev = mon_fdset_cur->id;
3737ef88b53SMarkus Armbruster                     continue;
3747ef88b53SMarkus Armbruster                 }
3757ef88b53SMarkus Armbruster                 break;
3767ef88b53SMarkus Armbruster             }
3777ef88b53SMarkus Armbruster         }
3787ef88b53SMarkus Armbruster 
3797ef88b53SMarkus Armbruster         mon_fdset = g_malloc0(sizeof(*mon_fdset));
3807ef88b53SMarkus Armbruster         if (has_fdset_id) {
3817ef88b53SMarkus Armbruster             mon_fdset->id = fdset_id;
3827ef88b53SMarkus Armbruster         } else {
3837ef88b53SMarkus Armbruster             mon_fdset->id = fdset_id_prev + 1;
3847ef88b53SMarkus Armbruster         }
3857ef88b53SMarkus Armbruster 
3867ef88b53SMarkus Armbruster         /* The fdset list is ordered by fdset ID */
3877ef88b53SMarkus Armbruster         if (!mon_fdset_cur) {
3887ef88b53SMarkus Armbruster             QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
3897ef88b53SMarkus Armbruster         } else if (mon_fdset->id < mon_fdset_cur->id) {
3907ef88b53SMarkus Armbruster             QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
3917ef88b53SMarkus Armbruster         } else {
3927ef88b53SMarkus Armbruster             QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
3937ef88b53SMarkus Armbruster         }
3947ef88b53SMarkus Armbruster     }
3957ef88b53SMarkus Armbruster 
3967ef88b53SMarkus Armbruster     mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
3977ef88b53SMarkus Armbruster     mon_fdset_fd->fd = fd;
3987ef88b53SMarkus Armbruster     mon_fdset_fd->removed = false;
3997ef88b53SMarkus Armbruster     mon_fdset_fd->opaque = g_strdup(opaque);
4007ef88b53SMarkus Armbruster     QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
4017ef88b53SMarkus Armbruster 
4027ef88b53SMarkus Armbruster     fdinfo = g_malloc0(sizeof(*fdinfo));
4037ef88b53SMarkus Armbruster     fdinfo->fdset_id = mon_fdset->id;
4047ef88b53SMarkus Armbruster     fdinfo->fd = mon_fdset_fd->fd;
4057ef88b53SMarkus Armbruster 
4067ef88b53SMarkus Armbruster     return fdinfo;
4077ef88b53SMarkus Armbruster }
4087ef88b53SMarkus Armbruster 
monitor_fdset_dup_fd_add(int64_t fdset_id,int flags)4097ef88b53SMarkus Armbruster int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags)
4107ef88b53SMarkus Armbruster {
4117ef88b53SMarkus Armbruster #ifdef _WIN32
4127ef88b53SMarkus Armbruster     return -ENOENT;
4137ef88b53SMarkus Armbruster #else
4147ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
4157ef88b53SMarkus Armbruster 
4167ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
4177ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
4187ef88b53SMarkus Armbruster         MonFdsetFd *mon_fdset_fd;
4197ef88b53SMarkus Armbruster         MonFdsetFd *mon_fdset_fd_dup;
4207ef88b53SMarkus Armbruster         int fd = -1;
4217ef88b53SMarkus Armbruster         int dup_fd;
4227ef88b53SMarkus Armbruster         int mon_fd_flags;
4237ef88b53SMarkus Armbruster 
4247ef88b53SMarkus Armbruster         if (mon_fdset->id != fdset_id) {
4257ef88b53SMarkus Armbruster             continue;
4267ef88b53SMarkus Armbruster         }
4277ef88b53SMarkus Armbruster 
4287ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
4297ef88b53SMarkus Armbruster             mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
4307ef88b53SMarkus Armbruster             if (mon_fd_flags == -1) {
4317ef88b53SMarkus Armbruster                 return -1;
4327ef88b53SMarkus Armbruster             }
4337ef88b53SMarkus Armbruster 
4347ef88b53SMarkus Armbruster             if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) {
4357ef88b53SMarkus Armbruster                 fd = mon_fdset_fd->fd;
4367ef88b53SMarkus Armbruster                 break;
4377ef88b53SMarkus Armbruster             }
4387ef88b53SMarkus Armbruster         }
4397ef88b53SMarkus Armbruster 
4407ef88b53SMarkus Armbruster         if (fd == -1) {
4417ef88b53SMarkus Armbruster             errno = EACCES;
4427ef88b53SMarkus Armbruster             return -1;
4437ef88b53SMarkus Armbruster         }
4447ef88b53SMarkus Armbruster 
4457ef88b53SMarkus Armbruster         dup_fd = qemu_dup_flags(fd, flags);
4467ef88b53SMarkus Armbruster         if (dup_fd == -1) {
4477ef88b53SMarkus Armbruster             return -1;
4487ef88b53SMarkus Armbruster         }
4497ef88b53SMarkus Armbruster 
4507ef88b53SMarkus Armbruster         mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
4517ef88b53SMarkus Armbruster         mon_fdset_fd_dup->fd = dup_fd;
4527ef88b53SMarkus Armbruster         QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
4537ef88b53SMarkus Armbruster         return dup_fd;
4547ef88b53SMarkus Armbruster     }
4557ef88b53SMarkus Armbruster 
4567ef88b53SMarkus Armbruster     errno = ENOENT;
4577ef88b53SMarkus Armbruster     return -1;
4587ef88b53SMarkus Armbruster #endif
4597ef88b53SMarkus Armbruster }
4607ef88b53SMarkus Armbruster 
monitor_fdset_dup_fd_find_remove(int dup_fd,bool remove)4617ef88b53SMarkus Armbruster static int64_t monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
4627ef88b53SMarkus Armbruster {
4637ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
4647ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd_dup;
4657ef88b53SMarkus Armbruster 
4667ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
4677ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
4687ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
4697ef88b53SMarkus Armbruster             if (mon_fdset_fd_dup->fd == dup_fd) {
4707ef88b53SMarkus Armbruster                 if (remove) {
4717ef88b53SMarkus Armbruster                     QLIST_REMOVE(mon_fdset_fd_dup, next);
4727ef88b53SMarkus Armbruster                     g_free(mon_fdset_fd_dup);
4737ef88b53SMarkus Armbruster                     if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
4747ef88b53SMarkus Armbruster                         monitor_fdset_cleanup(mon_fdset);
4757ef88b53SMarkus Armbruster                     }
4767ef88b53SMarkus Armbruster                     return -1;
4777ef88b53SMarkus Armbruster                 } else {
4787ef88b53SMarkus Armbruster                     return mon_fdset->id;
4797ef88b53SMarkus Armbruster                 }
4807ef88b53SMarkus Armbruster             }
4817ef88b53SMarkus Armbruster         }
4827ef88b53SMarkus Armbruster     }
4837ef88b53SMarkus Armbruster 
4847ef88b53SMarkus Armbruster     return -1;
4857ef88b53SMarkus Armbruster }
4867ef88b53SMarkus Armbruster 
monitor_fdset_dup_fd_find(int dup_fd)4877ef88b53SMarkus Armbruster int64_t monitor_fdset_dup_fd_find(int dup_fd)
4887ef88b53SMarkus Armbruster {
4897ef88b53SMarkus Armbruster     return monitor_fdset_dup_fd_find_remove(dup_fd, false);
4907ef88b53SMarkus Armbruster }
4917ef88b53SMarkus Armbruster 
monitor_fdset_dup_fd_remove(int dup_fd)4927ef88b53SMarkus Armbruster void monitor_fdset_dup_fd_remove(int dup_fd)
4937ef88b53SMarkus Armbruster {
4947ef88b53SMarkus Armbruster     monitor_fdset_dup_fd_find_remove(dup_fd, true);
4957ef88b53SMarkus Armbruster }
4967ef88b53SMarkus Armbruster 
monitor_fd_param(Monitor * mon,const char * fdname,Error ** errp)4977ef88b53SMarkus Armbruster int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp)
4987ef88b53SMarkus Armbruster {
4997ef88b53SMarkus Armbruster     int fd;
5007ef88b53SMarkus Armbruster 
5017ef88b53SMarkus Armbruster     if (!qemu_isdigit(fdname[0]) && mon) {
5027ef88b53SMarkus Armbruster         fd = monitor_get_fd(mon, fdname, errp);
5037ef88b53SMarkus Armbruster     } else {
5047ef88b53SMarkus Armbruster         fd = qemu_parse_fd(fdname);
5057ef88b53SMarkus Armbruster         if (fd < 0) {
5067ef88b53SMarkus Armbruster             error_setg(errp, "Invalid file descriptor number '%s'",
5077ef88b53SMarkus Armbruster                        fdname);
5087ef88b53SMarkus Armbruster         }
5097ef88b53SMarkus Armbruster     }
5107ef88b53SMarkus Armbruster 
5117ef88b53SMarkus Armbruster     return fd;
5127ef88b53SMarkus Armbruster }
5137ef88b53SMarkus Armbruster 
monitor_fds_init(void)5147ef88b53SMarkus Armbruster static void __attribute__((__constructor__)) monitor_fds_init(void)
5157ef88b53SMarkus Armbruster {
5167ef88b53SMarkus Armbruster     qemu_mutex_init(&mon_fdsets_lock);
5177ef88b53SMarkus Armbruster }
518