xref: /openbmc/qemu/monitor/fds.c (revision ffeddb979400b1580ad28acbee09b6f971c3912d)
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     char *opaque;
477ef88b53SMarkus Armbruster     QLIST_ENTRY(MonFdsetFd) next;
487ef88b53SMarkus Armbruster };
497ef88b53SMarkus Armbruster 
507ef88b53SMarkus Armbruster /* file descriptor set containing fds passed via SCM_RIGHTS */
517ef88b53SMarkus Armbruster typedef struct MonFdset MonFdset;
527ef88b53SMarkus Armbruster struct MonFdset {
537ef88b53SMarkus Armbruster     int64_t id;
547ef88b53SMarkus Armbruster     QLIST_HEAD(, MonFdsetFd) fds;
557ef88b53SMarkus Armbruster     QLIST_HEAD(, MonFdsetFd) dup_fds;
567ef88b53SMarkus Armbruster     QLIST_ENTRY(MonFdset) next;
577ef88b53SMarkus Armbruster };
587ef88b53SMarkus Armbruster 
597ef88b53SMarkus Armbruster /* Protects mon_fdsets */
607ef88b53SMarkus Armbruster static QemuMutex mon_fdsets_lock;
617ef88b53SMarkus Armbruster static QLIST_HEAD(, MonFdset) mon_fdsets;
627ef88b53SMarkus Armbruster 
monitor_add_fd(Monitor * mon,int fd,const char * fdname,Error ** errp)634cda177cSMarc-André Lureau static bool monitor_add_fd(Monitor *mon, int fd, const char *fdname, Error **errp)
644cda177cSMarc-André Lureau {
654cda177cSMarc-André Lureau     mon_fd_t *monfd;
664cda177cSMarc-André Lureau 
674cda177cSMarc-André Lureau     if (qemu_isdigit(fdname[0])) {
684cda177cSMarc-André Lureau         close(fd);
694cda177cSMarc-André Lureau         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname",
704cda177cSMarc-André Lureau                    "a name not starting with a digit");
714cda177cSMarc-André Lureau         return false;
724cda177cSMarc-André Lureau     }
734cda177cSMarc-André Lureau 
744cda177cSMarc-André Lureau     /* See close() call below. */
754cda177cSMarc-André Lureau     qemu_mutex_lock(&mon->mon_lock);
764cda177cSMarc-André Lureau     QLIST_FOREACH(monfd, &mon->fds, next) {
774cda177cSMarc-André Lureau         int tmp_fd;
784cda177cSMarc-André Lureau 
794cda177cSMarc-André Lureau         if (strcmp(monfd->name, fdname) != 0) {
804cda177cSMarc-André Lureau             continue;
814cda177cSMarc-André Lureau         }
824cda177cSMarc-André Lureau 
834cda177cSMarc-André Lureau         tmp_fd = monfd->fd;
844cda177cSMarc-André Lureau         monfd->fd = fd;
854cda177cSMarc-André Lureau         qemu_mutex_unlock(&mon->mon_lock);
864cda177cSMarc-André Lureau         /* Make sure close() is outside critical section */
874cda177cSMarc-André Lureau         close(tmp_fd);
884cda177cSMarc-André Lureau         return true;
894cda177cSMarc-André Lureau     }
904cda177cSMarc-André Lureau 
914cda177cSMarc-André Lureau     monfd = g_new0(mon_fd_t, 1);
924cda177cSMarc-André Lureau     monfd->name = g_strdup(fdname);
934cda177cSMarc-André Lureau     monfd->fd = fd;
944cda177cSMarc-André Lureau 
954cda177cSMarc-André Lureau     QLIST_INSERT_HEAD(&mon->fds, monfd, next);
964cda177cSMarc-André Lureau     qemu_mutex_unlock(&mon->mon_lock);
974cda177cSMarc-André Lureau     return true;
984cda177cSMarc-André Lureau }
994cda177cSMarc-André Lureau 
1004bf21c7fSMarc-André Lureau #ifdef CONFIG_POSIX
qmp_getfd(const char * fdname,Error ** errp)1017ef88b53SMarkus Armbruster void qmp_getfd(const char *fdname, Error **errp)
1027ef88b53SMarkus Armbruster {
1037ef88b53SMarkus Armbruster     Monitor *cur_mon = monitor_cur();
1044cda177cSMarc-André Lureau     int fd;
1057ef88b53SMarkus Armbruster 
1067ef88b53SMarkus Armbruster     fd = qemu_chr_fe_get_msgfd(&cur_mon->chr);
1077ef88b53SMarkus Armbruster     if (fd == -1) {
1087ef88b53SMarkus Armbruster         error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
1097ef88b53SMarkus Armbruster         return;
1107ef88b53SMarkus Armbruster     }
1117ef88b53SMarkus Armbruster 
1124cda177cSMarc-André Lureau     monitor_add_fd(cur_mon, fd, fdname, errp);
1137ef88b53SMarkus Armbruster }
1144bf21c7fSMarc-André Lureau #endif
1157ef88b53SMarkus Armbruster 
qmp_closefd(const char * fdname,Error ** errp)1167ef88b53SMarkus Armbruster void qmp_closefd(const char *fdname, Error **errp)
1177ef88b53SMarkus Armbruster {
1187ef88b53SMarkus Armbruster     Monitor *cur_mon = monitor_cur();
1197ef88b53SMarkus Armbruster     mon_fd_t *monfd;
1207ef88b53SMarkus Armbruster     int tmp_fd;
1217ef88b53SMarkus Armbruster 
1227ef88b53SMarkus Armbruster     qemu_mutex_lock(&cur_mon->mon_lock);
1237ef88b53SMarkus Armbruster     QLIST_FOREACH(monfd, &cur_mon->fds, next) {
1247ef88b53SMarkus Armbruster         if (strcmp(monfd->name, fdname) != 0) {
1257ef88b53SMarkus Armbruster             continue;
1267ef88b53SMarkus Armbruster         }
1277ef88b53SMarkus Armbruster 
1287ef88b53SMarkus Armbruster         QLIST_REMOVE(monfd, next);
1297ef88b53SMarkus Armbruster         tmp_fd = monfd->fd;
1307ef88b53SMarkus Armbruster         g_free(monfd->name);
1317ef88b53SMarkus Armbruster         g_free(monfd);
1327ef88b53SMarkus Armbruster         qemu_mutex_unlock(&cur_mon->mon_lock);
1337ef88b53SMarkus Armbruster         /* Make sure close() is outside critical section */
1347ef88b53SMarkus Armbruster         close(tmp_fd);
1357ef88b53SMarkus Armbruster         return;
1367ef88b53SMarkus Armbruster     }
1377ef88b53SMarkus Armbruster 
1387ef88b53SMarkus Armbruster     qemu_mutex_unlock(&cur_mon->mon_lock);
1397ef88b53SMarkus Armbruster     error_setg(errp, "File descriptor named '%s' not found", fdname);
1407ef88b53SMarkus Armbruster }
1417ef88b53SMarkus Armbruster 
monitor_get_fd(Monitor * mon,const char * fdname,Error ** errp)1427ef88b53SMarkus Armbruster int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
1437ef88b53SMarkus Armbruster {
1447ef88b53SMarkus Armbruster     mon_fd_t *monfd;
1457ef88b53SMarkus Armbruster 
1467ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon->mon_lock);
1477ef88b53SMarkus Armbruster     QLIST_FOREACH(monfd, &mon->fds, next) {
1487ef88b53SMarkus Armbruster         int fd;
1497ef88b53SMarkus Armbruster 
1507ef88b53SMarkus Armbruster         if (strcmp(monfd->name, fdname) != 0) {
1517ef88b53SMarkus Armbruster             continue;
1527ef88b53SMarkus Armbruster         }
1537ef88b53SMarkus Armbruster 
1547ef88b53SMarkus Armbruster         fd = monfd->fd;
1557ef88b53SMarkus Armbruster         assert(fd >= 0);
1567ef88b53SMarkus Armbruster 
1577ef88b53SMarkus Armbruster         /* caller takes ownership of fd */
1587ef88b53SMarkus Armbruster         QLIST_REMOVE(monfd, next);
1597ef88b53SMarkus Armbruster         g_free(monfd->name);
1607ef88b53SMarkus Armbruster         g_free(monfd);
1617ef88b53SMarkus Armbruster 
1627ef88b53SMarkus Armbruster         return fd;
1637ef88b53SMarkus Armbruster     }
1647ef88b53SMarkus Armbruster 
1657ef88b53SMarkus Armbruster     error_setg(errp, "File descriptor named '%s' has not been found", fdname);
1667ef88b53SMarkus Armbruster     return -1;
1677ef88b53SMarkus Armbruster }
1687ef88b53SMarkus Armbruster 
monitor_fdset_free(MonFdset * mon_fdset)169a93ad560SFabiano Rosas static void monitor_fdset_free(MonFdset *mon_fdset)
170a93ad560SFabiano Rosas {
171a93ad560SFabiano Rosas     QLIST_REMOVE(mon_fdset, next);
172a93ad560SFabiano Rosas     g_free(mon_fdset);
173a93ad560SFabiano Rosas }
174a93ad560SFabiano Rosas 
monitor_fdset_free_if_empty(MonFdset * mon_fdset)175a93ad560SFabiano Rosas static void monitor_fdset_free_if_empty(MonFdset *mon_fdset)
176a93ad560SFabiano Rosas {
17787d67fadSFabiano Rosas     /*
17887d67fadSFabiano Rosas      * Only remove an empty fdset. The fds are owned by the user and
17987d67fadSFabiano Rosas      * should have been removed with qmp_remove_fd(). The dup_fds are
18087d67fadSFabiano Rosas      * owned by QEMU and should have been removed with qemu_close().
18187d67fadSFabiano Rosas      */
182a93ad560SFabiano Rosas     if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) {
183a93ad560SFabiano Rosas         monitor_fdset_free(mon_fdset);
184a93ad560SFabiano Rosas     }
185a93ad560SFabiano Rosas }
186a93ad560SFabiano Rosas 
monitor_fdset_fd_free(MonFdsetFd * mon_fdset_fd)187a93ad560SFabiano Rosas static void monitor_fdset_fd_free(MonFdsetFd *mon_fdset_fd)
188a93ad560SFabiano Rosas {
189a93ad560SFabiano Rosas     close(mon_fdset_fd->fd);
190a93ad560SFabiano Rosas     g_free(mon_fdset_fd->opaque);
191a93ad560SFabiano Rosas     QLIST_REMOVE(mon_fdset_fd, next);
192a93ad560SFabiano Rosas     g_free(mon_fdset_fd);
193a93ad560SFabiano Rosas }
194a93ad560SFabiano Rosas 
monitor_fdsets_cleanup(void)1957ef88b53SMarkus Armbruster void monitor_fdsets_cleanup(void)
1967ef88b53SMarkus Armbruster {
1977ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
1987ef88b53SMarkus Armbruster     MonFdset *mon_fdset_next;
1997ef88b53SMarkus Armbruster 
2007ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
2017ef88b53SMarkus Armbruster     QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
20287d67fadSFabiano Rosas         monitor_fdset_free_if_empty(mon_fdset);
2037ef88b53SMarkus Armbruster     }
2047ef88b53SMarkus Armbruster }
2057ef88b53SMarkus Armbruster 
qmp_add_fd(bool has_fdset_id,int64_t fdset_id,const char * opaque,Error ** errp)2067ef88b53SMarkus Armbruster AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id,
2077ef88b53SMarkus Armbruster                       const char *opaque, Error **errp)
2087ef88b53SMarkus Armbruster {
2097ef88b53SMarkus Armbruster     int fd;
2107ef88b53SMarkus Armbruster     Monitor *mon = monitor_cur();
2117ef88b53SMarkus Armbruster     AddfdInfo *fdinfo;
2127ef88b53SMarkus Armbruster 
2137ef88b53SMarkus Armbruster     fd = qemu_chr_fe_get_msgfd(&mon->chr);
2147ef88b53SMarkus Armbruster     if (fd == -1) {
2157ef88b53SMarkus Armbruster         error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
2167ef88b53SMarkus Armbruster         goto error;
2177ef88b53SMarkus Armbruster     }
2187ef88b53SMarkus Armbruster 
2197ef88b53SMarkus Armbruster     fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp);
2207ef88b53SMarkus Armbruster     if (fdinfo) {
2217ef88b53SMarkus Armbruster         return fdinfo;
2227ef88b53SMarkus Armbruster     }
2237ef88b53SMarkus Armbruster 
2247ef88b53SMarkus Armbruster error:
2257ef88b53SMarkus Armbruster     if (fd != -1) {
2267ef88b53SMarkus Armbruster         close(fd);
2277ef88b53SMarkus Armbruster     }
2287ef88b53SMarkus Armbruster     return NULL;
2297ef88b53SMarkus Armbruster }
2307ef88b53SMarkus Armbruster 
2314cda177cSMarc-André Lureau #ifdef WIN32
qmp_get_win32_socket(const char * infos,const char * fdname,Error ** errp)2324cda177cSMarc-André Lureau void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp)
2334cda177cSMarc-André Lureau {
2344cda177cSMarc-André Lureau     g_autofree WSAPROTOCOL_INFOW *info = NULL;
2354cda177cSMarc-André Lureau     gsize len;
2364cda177cSMarc-André Lureau     SOCKET sk;
2374cda177cSMarc-André Lureau     int fd;
2384cda177cSMarc-André Lureau 
2394cda177cSMarc-André Lureau     info = (void *)g_base64_decode(infos, &len);
2404cda177cSMarc-André Lureau     if (len != sizeof(*info)) {
2414cda177cSMarc-André Lureau         error_setg(errp, "Invalid WSAPROTOCOL_INFOW value");
2424cda177cSMarc-André Lureau         return;
2434cda177cSMarc-André Lureau     }
2444cda177cSMarc-André Lureau 
2454cda177cSMarc-André Lureau     sk = WSASocketW(FROM_PROTOCOL_INFO,
2464cda177cSMarc-André Lureau                     FROM_PROTOCOL_INFO,
2474cda177cSMarc-André Lureau                     FROM_PROTOCOL_INFO,
2484cda177cSMarc-André Lureau                     info, 0, 0);
2494cda177cSMarc-André Lureau     if (sk == INVALID_SOCKET) {
2504cda177cSMarc-André Lureau         error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket");
2514cda177cSMarc-André Lureau         return;
2524cda177cSMarc-André Lureau     }
2534cda177cSMarc-André Lureau 
2544cda177cSMarc-André Lureau     fd = _open_osfhandle(sk, _O_BINARY);
2554cda177cSMarc-André Lureau     if (fd < 0) {
2564cda177cSMarc-André Lureau         error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET");
2574cda177cSMarc-André Lureau         closesocket(sk);
2584cda177cSMarc-André Lureau         return;
2594cda177cSMarc-André Lureau     }
2604cda177cSMarc-André Lureau 
2614cda177cSMarc-André Lureau     monitor_add_fd(monitor_cur(), fd, fdname, errp);
2624cda177cSMarc-André Lureau }
2634cda177cSMarc-André Lureau #endif
2644cda177cSMarc-André Lureau 
2654cda177cSMarc-André Lureau 
qmp_remove_fd(int64_t fdset_id,bool has_fd,int64_t fd,Error ** errp)2667ef88b53SMarkus Armbruster void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
2677ef88b53SMarkus Armbruster {
2687ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
269881172f3SFabiano Rosas     MonFdsetFd *mon_fdset_fd, *mon_fdset_fd_next;
2707ef88b53SMarkus Armbruster     char fd_str[60];
2717ef88b53SMarkus Armbruster 
2727ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
2737ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
2747ef88b53SMarkus Armbruster         if (mon_fdset->id != fdset_id) {
2757ef88b53SMarkus Armbruster             continue;
2767ef88b53SMarkus Armbruster         }
277881172f3SFabiano Rosas         QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next,
278881172f3SFabiano Rosas                            mon_fdset_fd_next) {
2797ef88b53SMarkus Armbruster             if (has_fd) {
2807ef88b53SMarkus Armbruster                 if (mon_fdset_fd->fd != fd) {
2817ef88b53SMarkus Armbruster                     continue;
2827ef88b53SMarkus Armbruster                 }
283881172f3SFabiano Rosas                 monitor_fdset_fd_free(mon_fdset_fd);
2847ef88b53SMarkus Armbruster                 break;
2857ef88b53SMarkus Armbruster             } else {
286881172f3SFabiano Rosas                 monitor_fdset_fd_free(mon_fdset_fd);
2877ef88b53SMarkus Armbruster             }
2887ef88b53SMarkus Armbruster         }
2897ef88b53SMarkus Armbruster         if (has_fd && !mon_fdset_fd) {
2907ef88b53SMarkus Armbruster             goto error;
2917ef88b53SMarkus Armbruster         }
292881172f3SFabiano Rosas         monitor_fdset_free_if_empty(mon_fdset);
2937ef88b53SMarkus Armbruster         return;
2947ef88b53SMarkus Armbruster     }
2957ef88b53SMarkus Armbruster 
2967ef88b53SMarkus Armbruster error:
2977ef88b53SMarkus Armbruster     if (has_fd) {
2987ef88b53SMarkus Armbruster         snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
2997ef88b53SMarkus Armbruster                  fdset_id, fd);
3007ef88b53SMarkus Armbruster     } else {
3017ef88b53SMarkus Armbruster         snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
3027ef88b53SMarkus Armbruster     }
3037ef88b53SMarkus Armbruster     error_setg(errp, "File descriptor named '%s' not found", fd_str);
3047ef88b53SMarkus Armbruster }
3057ef88b53SMarkus Armbruster 
qmp_query_fdsets(Error ** errp)3067ef88b53SMarkus Armbruster FdsetInfoList *qmp_query_fdsets(Error **errp)
3077ef88b53SMarkus Armbruster {
3087ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
3097ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd;
3107ef88b53SMarkus Armbruster     FdsetInfoList *fdset_list = NULL;
3117ef88b53SMarkus Armbruster 
3127ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
3137ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3147ef88b53SMarkus Armbruster         FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info));
3157ef88b53SMarkus Armbruster 
3167ef88b53SMarkus Armbruster         fdset_info->fdset_id = mon_fdset->id;
3177ef88b53SMarkus Armbruster 
3187ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
3197ef88b53SMarkus Armbruster             FdsetFdInfo *fdsetfd_info;
3207ef88b53SMarkus Armbruster 
3217ef88b53SMarkus Armbruster             fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
3227ef88b53SMarkus Armbruster             fdsetfd_info->fd = mon_fdset_fd->fd;
3237ef88b53SMarkus Armbruster             fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque);
3247ef88b53SMarkus Armbruster 
3257ef88b53SMarkus Armbruster             QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info);
3267ef88b53SMarkus Armbruster         }
3277ef88b53SMarkus Armbruster 
3287ef88b53SMarkus Armbruster         QAPI_LIST_PREPEND(fdset_list, fdset_info);
3297ef88b53SMarkus Armbruster     }
3307ef88b53SMarkus Armbruster 
3317ef88b53SMarkus Armbruster     return fdset_list;
3327ef88b53SMarkus Armbruster }
3337ef88b53SMarkus Armbruster 
monitor_fdset_add_fd(int fd,bool has_fdset_id,int64_t fdset_id,const char * opaque,Error ** errp)3347ef88b53SMarkus Armbruster AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
3357ef88b53SMarkus Armbruster                                 const char *opaque, Error **errp)
3367ef88b53SMarkus Armbruster {
3377ef88b53SMarkus Armbruster     MonFdset *mon_fdset = NULL;
3387ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd;
3397ef88b53SMarkus Armbruster     AddfdInfo *fdinfo;
3407ef88b53SMarkus Armbruster 
3417ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
3427ef88b53SMarkus Armbruster     if (has_fdset_id) {
3437ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3447ef88b53SMarkus Armbruster             /* Break if match found or match impossible due to ordering by ID */
3457ef88b53SMarkus Armbruster             if (fdset_id <= mon_fdset->id) {
3467ef88b53SMarkus Armbruster                 if (fdset_id < mon_fdset->id) {
3477ef88b53SMarkus Armbruster                     mon_fdset = NULL;
3487ef88b53SMarkus Armbruster                 }
3497ef88b53SMarkus Armbruster                 break;
3507ef88b53SMarkus Armbruster             }
3517ef88b53SMarkus Armbruster         }
3527ef88b53SMarkus Armbruster     }
3537ef88b53SMarkus Armbruster 
3547ef88b53SMarkus Armbruster     if (mon_fdset == NULL) {
3557ef88b53SMarkus Armbruster         int64_t fdset_id_prev = -1;
3567ef88b53SMarkus Armbruster         MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
3577ef88b53SMarkus Armbruster 
3587ef88b53SMarkus Armbruster         if (has_fdset_id) {
3597ef88b53SMarkus Armbruster             if (fdset_id < 0) {
3607ef88b53SMarkus Armbruster                 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
3617ef88b53SMarkus Armbruster                            "a non-negative value");
3627ef88b53SMarkus Armbruster                 return NULL;
3637ef88b53SMarkus Armbruster             }
3647ef88b53SMarkus Armbruster             /* Use specified fdset ID */
3657ef88b53SMarkus Armbruster             QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3667ef88b53SMarkus Armbruster                 mon_fdset_cur = mon_fdset;
3677ef88b53SMarkus Armbruster                 if (fdset_id < mon_fdset_cur->id) {
3687ef88b53SMarkus Armbruster                     break;
3697ef88b53SMarkus Armbruster                 }
3707ef88b53SMarkus Armbruster             }
3717ef88b53SMarkus Armbruster         } else {
3727ef88b53SMarkus Armbruster             /* Use first available fdset ID */
3737ef88b53SMarkus Armbruster             QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
3747ef88b53SMarkus Armbruster                 mon_fdset_cur = mon_fdset;
3757ef88b53SMarkus Armbruster                 if (fdset_id_prev == mon_fdset_cur->id - 1) {
3767ef88b53SMarkus Armbruster                     fdset_id_prev = mon_fdset_cur->id;
3777ef88b53SMarkus Armbruster                     continue;
3787ef88b53SMarkus Armbruster                 }
3797ef88b53SMarkus Armbruster                 break;
3807ef88b53SMarkus Armbruster             }
3817ef88b53SMarkus Armbruster         }
3827ef88b53SMarkus Armbruster 
3837ef88b53SMarkus Armbruster         mon_fdset = g_malloc0(sizeof(*mon_fdset));
3847ef88b53SMarkus Armbruster         if (has_fdset_id) {
3857ef88b53SMarkus Armbruster             mon_fdset->id = fdset_id;
3867ef88b53SMarkus Armbruster         } else {
3877ef88b53SMarkus Armbruster             mon_fdset->id = fdset_id_prev + 1;
3887ef88b53SMarkus Armbruster         }
3897ef88b53SMarkus Armbruster 
3907ef88b53SMarkus Armbruster         /* The fdset list is ordered by fdset ID */
3917ef88b53SMarkus Armbruster         if (!mon_fdset_cur) {
3927ef88b53SMarkus Armbruster             QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
3937ef88b53SMarkus Armbruster         } else if (mon_fdset->id < mon_fdset_cur->id) {
3947ef88b53SMarkus Armbruster             QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
3957ef88b53SMarkus Armbruster         } else {
3967ef88b53SMarkus Armbruster             QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
3977ef88b53SMarkus Armbruster         }
3987ef88b53SMarkus Armbruster     }
3997ef88b53SMarkus Armbruster 
4007ef88b53SMarkus Armbruster     mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
4017ef88b53SMarkus Armbruster     mon_fdset_fd->fd = fd;
4027ef88b53SMarkus Armbruster     mon_fdset_fd->opaque = g_strdup(opaque);
4037ef88b53SMarkus Armbruster     QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
4047ef88b53SMarkus Armbruster 
4057ef88b53SMarkus Armbruster     fdinfo = g_malloc0(sizeof(*fdinfo));
4067ef88b53SMarkus Armbruster     fdinfo->fdset_id = mon_fdset->id;
4077ef88b53SMarkus Armbruster     fdinfo->fd = mon_fdset_fd->fd;
4087ef88b53SMarkus Armbruster 
4097ef88b53SMarkus Armbruster     return fdinfo;
4107ef88b53SMarkus Armbruster }
4117ef88b53SMarkus Armbruster 
monitor_fdset_dup_fd_add(int64_t fdset_id,int flags,Error ** errp)412960f29b3SFabiano Rosas int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags, Error **errp)
4137ef88b53SMarkus Armbruster {
4147ef88b53SMarkus Armbruster #ifdef _WIN32
415960f29b3SFabiano Rosas     error_setg(errp, "Platform does not support fd passing (fdset)");
4167ef88b53SMarkus Armbruster     return -ENOENT;
4177ef88b53SMarkus Armbruster #else
4187ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
4197ef88b53SMarkus Armbruster 
4207ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
4217ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
4227ef88b53SMarkus Armbruster         MonFdsetFd *mon_fdset_fd;
4237ef88b53SMarkus Armbruster         MonFdsetFd *mon_fdset_fd_dup;
4247ef88b53SMarkus Armbruster         int fd = -1;
4257ef88b53SMarkus Armbruster         int dup_fd;
4267ef88b53SMarkus Armbruster         int mon_fd_flags;
427*99c147e2SFabiano Rosas         int mask = O_ACCMODE;
428*99c147e2SFabiano Rosas 
429*99c147e2SFabiano Rosas #ifdef O_DIRECT
430*99c147e2SFabiano Rosas         mask |= O_DIRECT;
431*99c147e2SFabiano Rosas #endif
4327ef88b53SMarkus Armbruster 
4337ef88b53SMarkus Armbruster         if (mon_fdset->id != fdset_id) {
4347ef88b53SMarkus Armbruster             continue;
4357ef88b53SMarkus Armbruster         }
4367ef88b53SMarkus Armbruster 
4377ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
4387ef88b53SMarkus Armbruster             mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
4397ef88b53SMarkus Armbruster             if (mon_fd_flags == -1) {
440960f29b3SFabiano Rosas                 error_setg(errp, "Failed to read file status flags for fd=%d",
441960f29b3SFabiano Rosas                            mon_fdset_fd->fd);
4427ef88b53SMarkus Armbruster                 return -1;
4437ef88b53SMarkus Armbruster             }
4447ef88b53SMarkus Armbruster 
445*99c147e2SFabiano Rosas             if ((flags & mask) == (mon_fd_flags & mask)) {
4467ef88b53SMarkus Armbruster                 fd = mon_fdset_fd->fd;
4477ef88b53SMarkus Armbruster                 break;
4487ef88b53SMarkus Armbruster             }
4497ef88b53SMarkus Armbruster         }
4507ef88b53SMarkus Armbruster 
4517ef88b53SMarkus Armbruster         if (fd == -1) {
4527ef88b53SMarkus Armbruster             errno = EACCES;
453960f29b3SFabiano Rosas             error_setg(errp,
454960f29b3SFabiano Rosas                        "Failed to find file descriptor with matching flags=0x%x",
455960f29b3SFabiano Rosas                        flags);
4567ef88b53SMarkus Armbruster             return -1;
4577ef88b53SMarkus Armbruster         }
4587ef88b53SMarkus Armbruster 
4597ef88b53SMarkus Armbruster         dup_fd = qemu_dup_flags(fd, flags);
4607ef88b53SMarkus Armbruster         if (dup_fd == -1) {
461960f29b3SFabiano Rosas             error_setg(errp, "Failed to dup() given file descriptor fd=%d", fd);
4627ef88b53SMarkus Armbruster             return -1;
4637ef88b53SMarkus Armbruster         }
4647ef88b53SMarkus Armbruster 
4657ef88b53SMarkus Armbruster         mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
4667ef88b53SMarkus Armbruster         mon_fdset_fd_dup->fd = dup_fd;
4677ef88b53SMarkus Armbruster         QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
4687ef88b53SMarkus Armbruster         return dup_fd;
4697ef88b53SMarkus Armbruster     }
4707ef88b53SMarkus Armbruster 
471960f29b3SFabiano Rosas     error_setg(errp, "Failed to find fdset /dev/fdset/%" PRId64, fdset_id);
4727ef88b53SMarkus Armbruster     errno = ENOENT;
4737ef88b53SMarkus Armbruster     return -1;
4747ef88b53SMarkus Armbruster #endif
4757ef88b53SMarkus Armbruster }
4767ef88b53SMarkus Armbruster 
monitor_fdset_dup_fd_remove(int dup_fd)4771cd93fb0SPeter Xu void monitor_fdset_dup_fd_remove(int dup_fd)
4787ef88b53SMarkus Armbruster {
4797ef88b53SMarkus Armbruster     MonFdset *mon_fdset;
4807ef88b53SMarkus Armbruster     MonFdsetFd *mon_fdset_fd_dup;
4817ef88b53SMarkus Armbruster 
4827ef88b53SMarkus Armbruster     QEMU_LOCK_GUARD(&mon_fdsets_lock);
4837ef88b53SMarkus Armbruster     QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
4847ef88b53SMarkus Armbruster         QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
4857ef88b53SMarkus Armbruster             if (mon_fdset_fd_dup->fd == dup_fd) {
4867ef88b53SMarkus Armbruster                 QLIST_REMOVE(mon_fdset_fd_dup, next);
4877ef88b53SMarkus Armbruster                 g_free(mon_fdset_fd_dup);
48887d67fadSFabiano Rosas                 monitor_fdset_free_if_empty(mon_fdset);
4891cd93fb0SPeter Xu                 return;
4907ef88b53SMarkus Armbruster             }
4917ef88b53SMarkus Armbruster         }
4927ef88b53SMarkus Armbruster     }
4937ef88b53SMarkus Armbruster }
4947ef88b53SMarkus Armbruster 
monitor_fd_param(Monitor * mon,const char * fdname,Error ** errp)4957ef88b53SMarkus Armbruster int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp)
4967ef88b53SMarkus Armbruster {
4977ef88b53SMarkus Armbruster     int fd;
4987ef88b53SMarkus Armbruster 
4997ef88b53SMarkus Armbruster     if (!qemu_isdigit(fdname[0]) && mon) {
5007ef88b53SMarkus Armbruster         fd = monitor_get_fd(mon, fdname, errp);
5017ef88b53SMarkus Armbruster     } else {
5027ef88b53SMarkus Armbruster         fd = qemu_parse_fd(fdname);
5037ef88b53SMarkus Armbruster         if (fd < 0) {
5047ef88b53SMarkus Armbruster             error_setg(errp, "Invalid file descriptor number '%s'",
5057ef88b53SMarkus Armbruster                        fdname);
5067ef88b53SMarkus Armbruster         }
5077ef88b53SMarkus Armbruster     }
5087ef88b53SMarkus Armbruster 
5097ef88b53SMarkus Armbruster     return fd;
5107ef88b53SMarkus Armbruster }
5117ef88b53SMarkus Armbruster 
monitor_fds_init(void)5127ef88b53SMarkus Armbruster static void __attribute__((__constructor__)) monitor_fds_init(void)
5137ef88b53SMarkus Armbruster {
5147ef88b53SMarkus Armbruster     qemu_mutex_init(&mon_fdsets_lock);
5157ef88b53SMarkus Armbruster }
516