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 /* 179 * Only remove an empty fdset. The fds are owned by the user and 180 * should have been removed with qmp_remove_fd(). The dup_fds are 181 * owned by QEMU and should have been removed with qemu_close(). 182 */ 183 if (QLIST_EMPTY(&mon_fdset->fds) && QLIST_EMPTY(&mon_fdset->dup_fds)) { 184 monitor_fdset_free(mon_fdset); 185 } 186 } 187 188 static void monitor_fdset_fd_free(MonFdsetFd *mon_fdset_fd) 189 { 190 close(mon_fdset_fd->fd); 191 g_free(mon_fdset_fd->opaque); 192 QLIST_REMOVE(mon_fdset_fd, next); 193 g_free(mon_fdset_fd); 194 } 195 196 static void monitor_fdset_cleanup(MonFdset *mon_fdset) 197 { 198 MonFdsetFd *mon_fdset_fd; 199 MonFdsetFd *mon_fdset_fd_next; 200 201 QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next, mon_fdset_fd_next) { 202 if (mon_fdset_fd->removed) { 203 monitor_fdset_fd_free(mon_fdset_fd); 204 } 205 } 206 207 monitor_fdset_free_if_empty(mon_fdset); 208 } 209 210 void monitor_fdsets_cleanup(void) 211 { 212 MonFdset *mon_fdset; 213 MonFdset *mon_fdset_next; 214 215 QEMU_LOCK_GUARD(&mon_fdsets_lock); 216 QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) { 217 monitor_fdset_free_if_empty(mon_fdset); 218 } 219 } 220 221 AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id, 222 const char *opaque, Error **errp) 223 { 224 int fd; 225 Monitor *mon = monitor_cur(); 226 AddfdInfo *fdinfo; 227 228 fd = qemu_chr_fe_get_msgfd(&mon->chr); 229 if (fd == -1) { 230 error_setg(errp, "No file descriptor supplied via SCM_RIGHTS"); 231 goto error; 232 } 233 234 fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp); 235 if (fdinfo) { 236 return fdinfo; 237 } 238 239 error: 240 if (fd != -1) { 241 close(fd); 242 } 243 return NULL; 244 } 245 246 #ifdef WIN32 247 void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp) 248 { 249 g_autofree WSAPROTOCOL_INFOW *info = NULL; 250 gsize len; 251 SOCKET sk; 252 int fd; 253 254 info = (void *)g_base64_decode(infos, &len); 255 if (len != sizeof(*info)) { 256 error_setg(errp, "Invalid WSAPROTOCOL_INFOW value"); 257 return; 258 } 259 260 sk = WSASocketW(FROM_PROTOCOL_INFO, 261 FROM_PROTOCOL_INFO, 262 FROM_PROTOCOL_INFO, 263 info, 0, 0); 264 if (sk == INVALID_SOCKET) { 265 error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket"); 266 return; 267 } 268 269 fd = _open_osfhandle(sk, _O_BINARY); 270 if (fd < 0) { 271 error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET"); 272 closesocket(sk); 273 return; 274 } 275 276 monitor_add_fd(monitor_cur(), fd, fdname, errp); 277 } 278 #endif 279 280 281 void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp) 282 { 283 MonFdset *mon_fdset; 284 MonFdsetFd *mon_fdset_fd; 285 char fd_str[60]; 286 287 QEMU_LOCK_GUARD(&mon_fdsets_lock); 288 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 289 if (mon_fdset->id != fdset_id) { 290 continue; 291 } 292 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 293 if (has_fd) { 294 if (mon_fdset_fd->fd != fd) { 295 continue; 296 } 297 mon_fdset_fd->removed = true; 298 break; 299 } else { 300 mon_fdset_fd->removed = true; 301 } 302 } 303 if (has_fd && !mon_fdset_fd) { 304 goto error; 305 } 306 monitor_fdset_cleanup(mon_fdset); 307 return; 308 } 309 310 error: 311 if (has_fd) { 312 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64, 313 fdset_id, fd); 314 } else { 315 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id); 316 } 317 error_setg(errp, "File descriptor named '%s' not found", fd_str); 318 } 319 320 FdsetInfoList *qmp_query_fdsets(Error **errp) 321 { 322 MonFdset *mon_fdset; 323 MonFdsetFd *mon_fdset_fd; 324 FdsetInfoList *fdset_list = NULL; 325 326 QEMU_LOCK_GUARD(&mon_fdsets_lock); 327 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 328 FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info)); 329 330 fdset_info->fdset_id = mon_fdset->id; 331 332 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 333 FdsetFdInfo *fdsetfd_info; 334 335 fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info)); 336 fdsetfd_info->fd = mon_fdset_fd->fd; 337 fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque); 338 339 QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info); 340 } 341 342 QAPI_LIST_PREPEND(fdset_list, fdset_info); 343 } 344 345 return fdset_list; 346 } 347 348 AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id, 349 const char *opaque, Error **errp) 350 { 351 MonFdset *mon_fdset = NULL; 352 MonFdsetFd *mon_fdset_fd; 353 AddfdInfo *fdinfo; 354 355 QEMU_LOCK_GUARD(&mon_fdsets_lock); 356 if (has_fdset_id) { 357 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 358 /* Break if match found or match impossible due to ordering by ID */ 359 if (fdset_id <= mon_fdset->id) { 360 if (fdset_id < mon_fdset->id) { 361 mon_fdset = NULL; 362 } 363 break; 364 } 365 } 366 } 367 368 if (mon_fdset == NULL) { 369 int64_t fdset_id_prev = -1; 370 MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets); 371 372 if (has_fdset_id) { 373 if (fdset_id < 0) { 374 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id", 375 "a non-negative value"); 376 return NULL; 377 } 378 /* Use specified fdset ID */ 379 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 380 mon_fdset_cur = mon_fdset; 381 if (fdset_id < mon_fdset_cur->id) { 382 break; 383 } 384 } 385 } else { 386 /* Use first available fdset ID */ 387 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 388 mon_fdset_cur = mon_fdset; 389 if (fdset_id_prev == mon_fdset_cur->id - 1) { 390 fdset_id_prev = mon_fdset_cur->id; 391 continue; 392 } 393 break; 394 } 395 } 396 397 mon_fdset = g_malloc0(sizeof(*mon_fdset)); 398 if (has_fdset_id) { 399 mon_fdset->id = fdset_id; 400 } else { 401 mon_fdset->id = fdset_id_prev + 1; 402 } 403 404 /* The fdset list is ordered by fdset ID */ 405 if (!mon_fdset_cur) { 406 QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next); 407 } else if (mon_fdset->id < mon_fdset_cur->id) { 408 QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next); 409 } else { 410 QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next); 411 } 412 } 413 414 mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd)); 415 mon_fdset_fd->fd = fd; 416 mon_fdset_fd->removed = false; 417 mon_fdset_fd->opaque = g_strdup(opaque); 418 QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next); 419 420 fdinfo = g_malloc0(sizeof(*fdinfo)); 421 fdinfo->fdset_id = mon_fdset->id; 422 fdinfo->fd = mon_fdset_fd->fd; 423 424 return fdinfo; 425 } 426 427 int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags) 428 { 429 #ifdef _WIN32 430 return -ENOENT; 431 #else 432 MonFdset *mon_fdset; 433 434 QEMU_LOCK_GUARD(&mon_fdsets_lock); 435 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 436 MonFdsetFd *mon_fdset_fd; 437 MonFdsetFd *mon_fdset_fd_dup; 438 int fd = -1; 439 int dup_fd; 440 int mon_fd_flags; 441 442 if (mon_fdset->id != fdset_id) { 443 continue; 444 } 445 446 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) { 447 mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL); 448 if (mon_fd_flags == -1) { 449 return -1; 450 } 451 452 if ((flags & O_ACCMODE) == (mon_fd_flags & O_ACCMODE)) { 453 fd = mon_fdset_fd->fd; 454 break; 455 } 456 } 457 458 if (fd == -1) { 459 errno = EACCES; 460 return -1; 461 } 462 463 dup_fd = qemu_dup_flags(fd, flags); 464 if (dup_fd == -1) { 465 return -1; 466 } 467 468 mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup)); 469 mon_fdset_fd_dup->fd = dup_fd; 470 QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next); 471 return dup_fd; 472 } 473 474 errno = ENOENT; 475 return -1; 476 #endif 477 } 478 479 void monitor_fdset_dup_fd_remove(int dup_fd) 480 { 481 MonFdset *mon_fdset; 482 MonFdsetFd *mon_fdset_fd_dup; 483 484 QEMU_LOCK_GUARD(&mon_fdsets_lock); 485 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) { 486 QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) { 487 if (mon_fdset_fd_dup->fd == dup_fd) { 488 QLIST_REMOVE(mon_fdset_fd_dup, next); 489 g_free(mon_fdset_fd_dup); 490 monitor_fdset_free_if_empty(mon_fdset); 491 return; 492 } 493 } 494 } 495 } 496 497 int monitor_fd_param(Monitor *mon, const char *fdname, Error **errp) 498 { 499 int fd; 500 501 if (!qemu_isdigit(fdname[0]) && mon) { 502 fd = monitor_get_fd(mon, fdname, errp); 503 } else { 504 fd = qemu_parse_fd(fdname); 505 if (fd < 0) { 506 error_setg(errp, "Invalid file descriptor number '%s'", 507 fdname); 508 } 509 } 510 511 return fd; 512 } 513 514 static void __attribute__((__constructor__)) monitor_fds_init(void) 515 { 516 qemu_mutex_init(&mon_fdsets_lock); 517 } 518