fds.c 14 KB

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