1 /* 2 * QEMU monitor file descriptor passing 3 * 4 * Copyright (c) 2003-2004 Fabrice Bellard 5 * 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: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 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 22 * THE SOFTWARE. 23 */ 24 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" 33 34 /* file descriptors passed via SCM_RIGHTS */ 35 typedef struct mon_fd_t mon_fd_t; 36 struct mon_fd_t { 37 char *name; 38 int fd; 39 QLIST_ENTRY(mon_fd_t) next; 40 }; 41 42 /* file descriptor associated with a file descriptor set */ 43 typedef struct MonFdsetFd MonFdsetFd; 44 struct MonFdsetFd { 45 int fd; 46 bool removed; 47 char *opaque; 48 QLIST_ENTRY(MonFdsetFd) next; 49 }; 50 51 /* file descriptor set containing fds passed via SCM_RIGHTS */ 52 typedef struct MonFdset MonFdset; 53 struct MonFdset { 54 int64_t id; 55 QLIST_HEAD(, MonFdsetFd) fds; 56 QLIST_HEAD(, MonFdsetFd) dup_fds; 57 QLIST_ENTRY(MonFdset) next; 58 }; 59 60 /* Protects mon_fdsets */ 61 static QemuMutex mon_fdsets_lock; 62 static QLIST_HEAD(, MonFdset) mon_fdsets; 63 64 static bool monitor_add_fd(Monitor *mon, int fd, const char *fdname, Error **errp) 65 { 66 mon_fd_t *monfd; 67 68 if (qemu_isdigit(fdname[0])) { 69 close(fd); 70 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdname", 71 "a name not starting with a digit"); 72 return false; 73 } 74 75 /* See close() call below. */ 76 qemu_mutex_lock(&mon->mon_lock); 77 QLIST_FOREACH(monfd, &mon->fds, next) { 78 int tmp_fd; 79 80 if (strcmp(monfd->name, fdname) != 0) { 81 continue; 82 } 83 84 tmp_fd = monfd->fd; 85 monfd->fd = fd; 86 qemu_mutex_unlock(&mon->mon_lock); 87 /* Make sure close() is outside critical section */ 88 close(tmp_fd); 89 return true; 90 } 91 92 monfd = g_new0(mon_fd_t, 1); 93 monfd->name = g_strdup(fdname); 94 monfd->fd = fd; 95 96 QLIST_INSERT_HEAD(&mon->fds, monfd, next); 97 qemu_mutex_unlock(&mon->mon_lock); 98 return true; 99 } 100 101 #ifdef CONFIG_POSIX 102 void qmp_getfd(const char *fdname, Error **errp) 103 { 104 Monitor *cur_mon = monitor_cur(); 105 int fd; 106 107 fd = qemu_chr_fe_get_msgfd(&cur_mon->chr); 108 if (fd == -1) { 109 error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); 110 return; 111 } 112 113 monitor_add_fd(cur_mon, fd, fdname, errp); 114 } 115 #endif 116 117 void qmp_closefd(const char *fdname, Error **errp) 118 { 119 Monitor *cur_mon = monitor_cur(); 120 mon_fd_t *monfd; 121 int tmp_fd; 122 123 qemu_mutex_lock(&cur_mon->mon_lock); 124 QLIST_FOREACH(monfd, &cur_mon->fds, next) { 125 if (strcmp(monfd->name, fdname) != 0) { 126 continue; 127 } 128 129 QLIST_REMOVE(monfd, next); 130 tmp_fd = monfd->fd; 131 g_free(monfd->name); 132 g_free(monfd); 133 qemu_mutex_unlock(&cur_mon->mon_lock); 134 /* Make sure close() is outside critical section */ 135 close(tmp_fd); 136 return; 137 } 138 139 qemu_mutex_unlock(&cur_mon->mon_lock); 140 error_setg(errp, "File descriptor named '%s' not found", fdname); 141 } 142 143 int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) 144 { 145 mon_fd_t *monfd; 146 147 QEMU_LOCK_GUARD(&mon->mon_lock); 148 QLIST_FOREACH(monfd, &mon->fds, next) { 149 int fd; 150 151 if (strcmp(monfd->name, fdname) != 0) { 152 continue; 153 } 154 155 fd = monfd->fd; 156 assert(fd >= 0); 157 158 /* caller takes ownership of fd */ 159 QLIST_REMOVE(monfd, next); 160 g_free(monfd->name); 161 g_free(monfd); 162 163 return fd; 164 } 165 166 error_setg(errp, "File descriptor named '%s' has not been found", fdname); 167 return -1; 168 } 169 170 static void monitor_fdset_free(MonFdset *mon_fdset) 171 { 172 QLIST_REMOVE(mon_fdset, next); 173 g_free(mon_fdset); 174 } 175 176 static void monitor_fdset_free_if_empty(MonFdset *mon_fdset) 177 { 178 if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) { 179 monitor_fdset_free(mon_fdset); 180 } 181 } 182 183 static void monitor_fdset_fd_free(MonFdsetFd *mon_fdset_fd) 184 { 185 close(mon_fdset_fd->fd); 186 g_free(mon_fdset_fd->opaque); 187 QLIST_REMOVE(mon_fdset_fd, next); 188 g_free(mon_fdset_fd); 189 } 190 191 static void monitor_fdset_cleanup(MonFdset *mon_fdset) 192 { 193 MonFdsetFd *mon_fdset_fd; 194 MonFdsetFd *mon_fdset_fd_next; 195 196 QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) { 197 if ((mon_fdset_fd->removed || 198 (QLIST_EMPTY(&mon_fdset->dup_fds) && mon_refcount == 0)) && 199 runstate_is_running()) { 200 monitor_fdset_fd_free(mon_fdset_fd); 201 } 202 } 203 204 monitor_fdset_free_if_empty(mon_fdset); 205 } 206 207 void monitor_fdsets_cleanup(void) 208 { 209 MonFdset *mon_fdset; 210 MonFdset *mon_fdset_next; 211 212 QEMU_LOCK_GUARD(&mon_fdsets_lock); 213 QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { 214 monitor_fdset_cleanup(mon_fdset); 215 } 216 } 217 218 AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, 219 const char *opaque, Error **errp) 220 { 221 int fd; 222 Monitor *mon = monitor_cur(); 223 AddfdInfo *fdinfo; 224 225 fd = qemu_chr_fe_get_msgfd(&mon->chr); 226 if (fd == -1) { 227 error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); 228 goto error; 229 } 230 231 fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp); 232 if (fdinfo) { 233 return fdinfo; 234 } 235 236 error: 237 if (fd != -1) { 238 close(fd); 239 } 240 return NULL; 241 } 242 243 #ifdef WIN32 244 void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp) 245 { 246 g_autofree WSAPROTOCOL_INFOW *info = NULL; 247 gsize len; 248 SOCKET sk; 249 int fd; 250 251 info = (void *)g_base64_decode(infos, &len); 252 if (len != sizeof(*info)) { 253 error_setg(errp, "Invalid WSAPROTOCOL_INFOW value"); 254 return; 255 } 256 257 sk = WSASocketW(FROM_PROTOCOL_INFO, 258 FROM_PROTOCOL_INFO, 259 FROM_PROTOCOL_INFO, 260 info, 0, 0); 261 if (sk == INVALID_SOCKET) { 262 error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket"); 263 return; 264 } 265 266 fd = _open_osfhandle(sk, _O_BINARY); 267 if (fd < 0) { 268 error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET"); 269 closesocket(sk); 270 return; 271 } 272 273 monitor_add_fd(monitor_cur(), fd, fdname, errp); 274 } 275 #endif 276 277 278 void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) 279 { 280 MonFdset *mon_fdset; 281 MonFdsetFd *mon_fdset_fd; 282 char fd_str[60]; 283 284 QEMU_LOCK_GUARD(&mon_fdsets_lock); 285 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 286 if (mon_fdset->id != fdset_id) { 287 continue; 288 } 289 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 290 if (has_fd) { 291 if (mon_fdset_fd->fd != fd) { 292 continue; 293 } 294 mon_fdset_fd->removed = true; 295 break; 296 } else { 297 mon_fdset_fd->removed = true; 298 } 299 } 300 if (has_fd && !mon_fdset_fd) { 301 goto error; 302 } 303 monitor_fdset_cleanup(mon_fdset); 304 return; 305 } 306 307 error: 308 if (has_fd) { 309 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, 310 fdset_id, fd); 311 } else { 312 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id); 313 } 314 error_setg(errp, "File descriptor named '%s' not found", fd_str); 315 } 316 317 FdsetInfoList *qmp_query_fdsets(Error **errp) 318 { 319 MonFdset *mon_fdset; 320 MonFdsetFd *mon_fdset_fd; 321 FdsetInfoList *fdset_list = NULL; 322 323 QEMU_LOCK_GUARD(&mon_fdsets_lock); 324 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 325 FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info)); 326 327 fdset_info->fdset_id = mon_fdset->id; 328 329 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 330 FdsetFdInfo *fdsetfd_info; 331 332 fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); 333 fdsetfd_info->fd = mon_fdset_fd->fd; 334 fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque); 335 336 QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info); 337 } 338 339 QAPI_LIST_PREPEND(fdset_list, fdset_info); 340 } 341 342 return fdset_list; 343 } 344 345 AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, 346 const char *opaque, Error **errp) 347 { 348 MonFdset *mon_fdset = NULL; 349 MonFdsetFd *mon_fdset_fd; 350 AddfdInfo *fdinfo; 351 352 QEMU_LOCK_GUARD(&mon_fdsets_lock); 353 if (has_fdset_id) { 354 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 355 /* Break if match found or match impossible due to ordering by ID */ 356 if (fdset_id <= mon_fdset->id) { 357 if (fdset_id < mon_fdset->id) { 358 mon_fdset = NULL; 359 } 360 break; 361 } 362 } 363 } 364 365 if (mon_fdset == NULL) { 366 int64_t fdset_id_prev = -1; 367 MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets); 368 369 if (has_fdset_id) { 370 if (fdset_id < 0) { 371 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", 372 "a non-negative value"); 373 return NULL; 374 } 375 /* Use specified fdset ID */ 376 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 377 mon_fdset_cur = mon_fdset; 378 if (fdset_id < mon_fdset_cur->id) { 379 break; 380 } 381 } 382 } else { 383 /* Use first available fdset ID */ 384 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 385 mon_fdset_cur = mon_fdset; 386 if (fdset_id_prev == mon_fdset_cur->id - 1) { 387 fdset_id_prev = mon_fdset_cur->id; 388 continue; 389 } 390 break; 391 } 392 } 393 394 mon_fdset = g_malloc0(sizeof(*mon_fdset)); 395 if (has_fdset_id) { 396 mon_fdset->id = fdset_id; 397 } else { 398 mon_fdset->id = fdset_id_prev + 1; 399 } 400 401 /* The fdset list is ordered by fdset ID */ 402 if (!mon_fdset_cur) { 403 QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next); 404 } else if (mon_fdset->id < mon_fdset_cur->id) { 405 QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next); 406 } else { 407 QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next); 408 } 409 } 410 411 mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); 412 mon_fdset_fd->fd = fd; 413 mon_fdset_fd->removed = false; 414 mon_fdset_fd->opaque = g_strdup(opaque); 415 QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); 416 417 fdinfo = g_malloc0(sizeof(*fdinfo)); 418 fdinfo->fdset_id = mon_fdset->id; 419 fdinfo->fd = mon_fdset_fd->fd; 420 421 return fdinfo; 422 } 423 424 int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags) 425 { 426 #ifdef _WIN32 427 return -ENOENT; 428 #else 429 MonFdset *mon_fdset; 430 431 QEMU_LOCK_GUARD(&mon_fdsets_lock); 432 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 433 MonFdsetFd *mon_fdset_fd; 434 MonFdsetFd *mon_fdset_fd_dup; 435 int fd = -1; 436 int dup_fd; 437 int mon_fd_flags; 438 439 if (mon_fdset->id != fdset_id) { 440 continue; 441 } 442 443 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 444 mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); 445 if (mon_fd_flags == -1) { 446 return -1; 447 } 448 449 if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { 450 fd = mon_fdset_fd->fd; 451 break; 452 } 453 } 454 455 if (fd == -1) { 456 errno = EACCES; 457 return -1; 458 } 459 460 dup_fd = qemu_dup_flags(fd, flags); 461 if (dup_fd == -1) { 462 return -1; 463 } 464 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); 468 return dup_fd; 469 } 470 471 errno = ENOENT; 472 return -1; 473 #endif 474 } 475 476 void monitor_fdset_dup_fd_remove(int dup_fd) 477 { 478 MonFdset *mon_fdset; 479 MonFdsetFd *mon_fdset_fd_dup; 480 481 QEMU_LOCK_GUARD(&mon_fdsets_lock); 482 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 483 QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { 484 if (mon_fdset_fd_dup->fd == dup_fd) { 485 QLIST_REMOVE(mon_fdset_fd_dup, next); 486 g_free(mon_fdset_fd_dup); 487 if (QLIST_EMPTY(&mon_fdset->dup_fds)) { 488 monitor_fdset_cleanup(mon_fdset); 489 } 490 return; 491 } 492 } 493 } 494 } 495 496 int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp) 497 { 498 int fd; 499 500 if (!qemu_isdigit(fdname[0]) && mon) { 501 fd = monitor_get_fd(mon, fdname, errp); 502 } else { 503 fd = qemu_parse_fd(fdname); 504 if (fd < 0) { 505 error_setg(errp, "Invalid file descriptor number '%s'", 506 fdname); 507 } 508 } 509 510 return fd; 511 } 512 513 static void __attribute__((__constructor__)) monitor_fds_init(void) 514 { 515 qemu_mutex_init(&mon_fdsets_lock); 516 } 517