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