master
c 516 lines 14 KB
Raw
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 "qemu/lockable.h"
33 #include "system/runstate.h"
34
35 /* file descriptors passed via SCM_RIGHTS */
36 typedef struct mon_fd_t mon_fd_t;
37 struct mon_fd_t {
38 char *name;
39 int fd;
40 QLIST_ENTRY(mon_fd_t) next;
41 };
42
43 /* file descriptor associated with a file descriptor set */
44 typedef struct MonFdsetFd MonFdsetFd;
45 struct MonFdsetFd {
46 int fd;
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 void monitor_fdsets_cleanup(void)
197 {
198 MonFdset *mon_fdset;
199 MonFdset *mon_fdset_next;
200
201 QEMU_LOCK_GUARD(&mon_fdsets_lock);
202 QLIST_FOREACH_SAFE(mon_fdset, &mon_fdsets, next, mon_fdset_next) {
203 monitor_fdset_free_if_empty(mon_fdset);
204 }
205 }
206
207 AddfdInfo *qmp_add_fd(bool has_fdset_id, int64_t fdset_id,
208 const char *opaque, Error **errp)
209 {
210 int fd;
211 Monitor *mon = monitor_cur();
212 AddfdInfo *fdinfo;
213
214 fd = qemu_chr_fe_get_msgfd(&mon->chr);
215 if (fd == -1) {
216 error_setg(errp, "No file descriptor supplied via SCM_RIGHTS");
217 goto error;
218 }
219
220 fdinfo = monitor_fdset_add_fd(fd, has_fdset_id, fdset_id, opaque, errp);
221 if (fdinfo) {
222 return fdinfo;
223 }
224
225 error:
226 if (fd != -1) {
227 close(fd);
228 }
229 return NULL;
230 }
231
232 #ifdef WIN32
233 void qmp_get_win32_socket(const char *infos, const char *fdname, Error **errp)
234 {
235 g_autofree WSAPROTOCOL_INFOW *info = NULL;
236 gsize len;
237 SOCKET sk;
238 int fd;
239
240 info = (void *)g_base64_decode(infos, &len);
241 if (len != sizeof(*info)) {
242 error_setg(errp, "Invalid WSAPROTOCOL_INFOW value");
243 return;
244 }
245
246 sk = WSASocketW(FROM_PROTOCOL_INFO,
247 FROM_PROTOCOL_INFO,
248 FROM_PROTOCOL_INFO,
249 info, 0, 0);
250 if (sk == INVALID_SOCKET) {
251 error_setg_win32(errp, WSAGetLastError(), "Couldn't import socket");
252 return;
253 }
254
255 fd = _open_osfhandle(sk, _O_BINARY);
256 if (fd < 0) {
257 error_setg_errno(errp, errno, "Failed to associate a FD with the SOCKET");
258 closesocket(sk);
259 return;
260 }
261
262 monitor_add_fd(monitor_cur(), fd, fdname, errp);
263 }
264 #endif
265
266
267 void qmp_remove_fd(int64_t fdset_id, bool has_fd, int64_t fd, Error **errp)
268 {
269 MonFdset *mon_fdset;
270 MonFdsetFd *mon_fdset_fd, *mon_fdset_fd_next;
271 char fd_str[60];
272
273 QEMU_LOCK_GUARD(&mon_fdsets_lock);
274 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
275 if (mon_fdset->id != fdset_id) {
276 continue;
277 }
278 QLIST_FOREACH_SAFE(mon_fdset_fd, &mon_fdset->fds, next,
279 mon_fdset_fd_next) {
280 if (has_fd) {
281 if (mon_fdset_fd->fd != fd) {
282 continue;
283 }
284 monitor_fdset_fd_free(mon_fdset_fd);
285 break;
286 } else {
287 monitor_fdset_fd_free(mon_fdset_fd);
288 }
289 }
290 if (has_fd && !mon_fdset_fd) {
291 goto error;
292 }
293 monitor_fdset_free_if_empty(mon_fdset);
294 return;
295 }
296
297 error:
298 if (has_fd) {
299 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64 ", fd:%" PRId64,
300 fdset_id, fd);
301 } else {
302 snprintf(fd_str, sizeof(fd_str), "fdset-id:%" PRId64, fdset_id);
303 }
304 error_setg(errp, "File descriptor named '%s' not found", fd_str);
305 }
306
307 FdsetInfoList *qmp_query_fdsets(Error **errp)
308 {
309 MonFdset *mon_fdset;
310 MonFdsetFd *mon_fdset_fd;
311 FdsetInfoList *fdset_list = NULL;
312
313 QEMU_LOCK_GUARD(&mon_fdsets_lock);
314 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
315 FdsetInfo *fdset_info = g_malloc0(sizeof(*fdset_info));
316
317 fdset_info->fdset_id = mon_fdset->id;
318
319 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
320 FdsetFdInfo *fdsetfd_info;
321
322 fdsetfd_info = g_malloc0(sizeof(*fdsetfd_info));
323 fdsetfd_info->fd = mon_fdset_fd->fd;
324 fdsetfd_info->opaque = g_strdup(mon_fdset_fd->opaque);
325
326 QAPI_LIST_PREPEND(fdset_info->fds, fdsetfd_info);
327 }
328
329 QAPI_LIST_PREPEND(fdset_list, fdset_info);
330 }
331
332 return fdset_list;
333 }
334
335 AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
336 const char *opaque, Error **errp)
337 {
338 MonFdset *mon_fdset = NULL;
339 MonFdsetFd *mon_fdset_fd;
340 AddfdInfo *fdinfo;
341
342 QEMU_LOCK_GUARD(&mon_fdsets_lock);
343 if (has_fdset_id) {
344 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
345 /* Break if match found or match impossible due to ordering by ID */
346 if (fdset_id <= mon_fdset->id) {
347 if (fdset_id < mon_fdset->id) {
348 mon_fdset = NULL;
349 }
350 break;
351 }
352 }
353 }
354
355 if (mon_fdset == NULL) {
356 int64_t fdset_id_prev = -1;
357 MonFdset *mon_fdset_cur = QLIST_FIRST(&mon_fdsets);
358
359 if (has_fdset_id) {
360 if (fdset_id < 0) {
361 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "fdset-id",
362 "a non-negative value");
363 return NULL;
364 }
365 /* Use specified fdset ID */
366 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
367 mon_fdset_cur = mon_fdset;
368 if (fdset_id < mon_fdset_cur->id) {
369 break;
370 }
371 }
372 } else {
373 /* Use first available fdset ID */
374 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
375 mon_fdset_cur = mon_fdset;
376 if (fdset_id_prev == mon_fdset_cur->id - 1) {
377 fdset_id_prev = mon_fdset_cur->id;
378 continue;
379 }
380 break;
381 }
382 }
383
384 mon_fdset = g_malloc0(sizeof(*mon_fdset));
385 if (has_fdset_id) {
386 mon_fdset->id = fdset_id;
387 } else {
388 mon_fdset->id = fdset_id_prev + 1;
389 }
390
391 /* The fdset list is ordered by fdset ID */
392 if (!mon_fdset_cur) {
393 QLIST_INSERT_HEAD(&mon_fdsets, mon_fdset, next);
394 } else if (mon_fdset->id < mon_fdset_cur->id) {
395 QLIST_INSERT_BEFORE(mon_fdset_cur, mon_fdset, next);
396 } else {
397 QLIST_INSERT_AFTER(mon_fdset_cur, mon_fdset, next);
398 }
399 }
400
401 mon_fdset_fd = g_malloc0(sizeof(*mon_fdset_fd));
402 mon_fdset_fd->fd = fd;
403 mon_fdset_fd->opaque = g_strdup(opaque);
404 QLIST_INSERT_HEAD(&mon_fdset->fds, mon_fdset_fd, next);
405
406 fdinfo = g_malloc0(sizeof(*fdinfo));
407 fdinfo->fdset_id = mon_fdset->id;
408 fdinfo->fd = mon_fdset_fd->fd;
409
410 return fdinfo;
411 }
412
413 int monitor_fdset_dup_fd_add(int64_t fdset_id, int flags, Error **errp)
414 {
415 #ifdef _WIN32
416 error_setg(errp, "Platform does not support fd passing (fdset)");
417 return -ENOENT;
418 #else
419 MonFdset *mon_fdset;
420
421 QEMU_LOCK_GUARD(&mon_fdsets_lock);
422 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
423 MonFdsetFd *mon_fdset_fd;
424 MonFdsetFd *mon_fdset_fd_dup;
425 int fd = -1;
426 int dup_fd;
427 int mon_fd_flags;
428 int mask = O_ACCMODE;
429
430 #ifdef O_DIRECT
431 mask |= O_DIRECT;
432 #endif
433
434 if (mon_fdset->id != fdset_id) {
435 continue;
436 }
437
438 QLIST_FOREACH(mon_fdset_fd, &mon_fdset->fds, next) {
439 mon_fd_flags = fcntl(mon_fdset_fd->fd, F_GETFL);
440 if (mon_fd_flags == -1) {
441 error_setg(errp, "Failed to read file status flags for fd=%d",
442 mon_fdset_fd->fd);
443 return -1;
444 }
445
446 if ((flags & mask) == (mon_fd_flags & mask)) {
447 fd = mon_fdset_fd->fd;
448 break;
449 }
450 }
451
452 if (fd == -1) {
453 errno = EACCES;
454 error_setg(errp,
455 "Failed to find file descriptor with matching flags=0x%x",
456 flags);
457 return -1;
458 }
459
460 dup_fd = qemu_dup_flags(fd, flags);
461 if (dup_fd == -1) {
462 error_setg(errp, "Failed to dup() given file descriptor fd=%d", fd);
463 return -1;
464 }
465
466 mon_fdset_fd_dup = g_malloc0(sizeof(*mon_fdset_fd_dup));
467 mon_fdset_fd_dup->fd = dup_fd;
468 QLIST_INSERT_HEAD(&mon_fdset->dup_fds, mon_fdset_fd_dup, next);
469 return dup_fd;
470 }
471
472 error_setg(errp, "Failed to find fdset /dev/fdset/%" PRId64, fdset_id);
473 errno = ENOENT;
474 return -1;
475 #endif
476 }
477
478 void monitor_fdset_dup_fd_remove(int dup_fd)
479 {
480 MonFdset *mon_fdset;
481 MonFdsetFd *mon_fdset_fd_dup;
482
483 QEMU_LOCK_GUARD(&mon_fdsets_lock);
484 QLIST_FOREACH(mon_fdset, &mon_fdsets, next) {
485 QLIST_FOREACH(mon_fdset_fd_dup, &mon_fdset->dup_fds, next) {
486 if (mon_fdset_fd_dup->fd == dup_fd) {
487 QLIST_REMOVE(mon_fdset_fd_dup, next);
488 g_free(mon_fdset_fd_dup);
489 monitor_fdset_free_if_empty(mon_fdset);
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 }