fds.c 14 KB

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