commands-bsd.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * QEMU Guest Agent BSD-specific command implementations
  3. *
  4. * Copyright (c) Virtuozzo International GmbH.
  5. *
  6. * Authors:
  7. * Alexander Ivanov <alexander.ivanov@virtuozzo.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. */
  12. #include "qemu/osdep.h"
  13. #include "qga-qapi-commands.h"
  14. #include "qapi/error.h"
  15. #include "qemu/queue.h"
  16. #include "commands-common.h"
  17. #include <sys/ioctl.h>
  18. #include <sys/param.h>
  19. #include <sys/ucred.h>
  20. #include <sys/mount.h>
  21. #include <net/if_dl.h>
  22. #if defined(__NetBSD__) || defined(__OpenBSD__)
  23. #include <net/if_arp.h>
  24. #include <netinet/if_ether.h>
  25. #else
  26. #include <net/ethernet.h>
  27. #endif
  28. #include <paths.h>
  29. #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
  30. bool build_fs_mount_list(FsMountList *mounts, Error **errp)
  31. {
  32. FsMount *mount;
  33. struct statfs *mntbuf, *mntp;
  34. struct stat statbuf;
  35. int i, count, ret;
  36. count = getmntinfo(&mntbuf, MNT_NOWAIT);
  37. if (count == 0) {
  38. error_setg_errno(errp, errno, "getmntinfo failed");
  39. return false;
  40. }
  41. for (i = 0; i < count; i++) {
  42. mntp = &mntbuf[i];
  43. ret = stat(mntp->f_mntonname, &statbuf);
  44. if (ret != 0) {
  45. error_setg_errno(errp, errno, "stat failed on %s",
  46. mntp->f_mntonname);
  47. return false;
  48. }
  49. mount = g_new0(FsMount, 1);
  50. mount->dirname = g_strdup(mntp->f_mntonname);
  51. mount->devtype = g_strdup(mntp->f_fstypename);
  52. mount->devmajor = major(mount->dev);
  53. mount->devminor = minor(mount->dev);
  54. mount->fsid = mntp->f_fsid;
  55. mount->dev = statbuf.st_dev;
  56. QTAILQ_INSERT_TAIL(mounts, mount, next);
  57. }
  58. return true;
  59. }
  60. #endif /* CONFIG_FSFREEZE || CONFIG_FSTRIM */
  61. #if defined(CONFIG_FSFREEZE)
  62. static int ufssuspend_fd = -1;
  63. static int ufssuspend_cnt;
  64. int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints,
  65. strList *mountpoints,
  66. FsMountList mounts,
  67. Error **errp)
  68. {
  69. int ret;
  70. strList *list;
  71. struct FsMount *mount;
  72. if (ufssuspend_fd != -1) {
  73. error_setg(errp, "filesystems have already frozen");
  74. return -1;
  75. }
  76. ufssuspend_cnt = 0;
  77. ufssuspend_fd = qemu_open(_PATH_UFSSUSPEND, O_RDWR, errp);
  78. if (ufssuspend_fd == -1) {
  79. return -1;
  80. }
  81. QTAILQ_FOREACH_REVERSE(mount, &mounts, next) {
  82. /*
  83. * To issue fsfreeze in the reverse order of mounts, check if the
  84. * mount is listed in the list here
  85. */
  86. if (has_mountpoints) {
  87. for (list = mountpoints; list; list = list->next) {
  88. if (g_str_equal(list->value, mount->dirname)) {
  89. break;
  90. }
  91. }
  92. if (!list) {
  93. continue;
  94. }
  95. }
  96. /* Only UFS supports suspend */
  97. if (!g_str_equal(mount->devtype, "ufs")) {
  98. continue;
  99. }
  100. ret = ioctl(ufssuspend_fd, UFSSUSPEND, &mount->fsid);
  101. if (ret == -1) {
  102. /*
  103. * ioctl returns EBUSY for all the FS except the first one
  104. * that was suspended
  105. */
  106. if (errno == EBUSY) {
  107. continue;
  108. }
  109. error_setg_errno(errp, errno, "failed to freeze %s",
  110. mount->dirname);
  111. goto error;
  112. }
  113. ufssuspend_cnt++;
  114. }
  115. return ufssuspend_cnt;
  116. error:
  117. close(ufssuspend_fd);
  118. ufssuspend_fd = -1;
  119. return -1;
  120. }
  121. /*
  122. * We don't need to call UFSRESUME ioctl because all the frozen FS
  123. * are thawed on /dev/ufssuspend closing.
  124. */
  125. int qmp_guest_fsfreeze_do_thaw(Error **errp)
  126. {
  127. int ret = ufssuspend_cnt;
  128. ufssuspend_cnt = 0;
  129. if (ufssuspend_fd != -1) {
  130. close(ufssuspend_fd);
  131. ufssuspend_fd = -1;
  132. }
  133. return ret;
  134. }
  135. #endif /* CONFIG_FSFREEZE */
  136. #ifdef HAVE_GETIFADDRS
  137. /*
  138. * Fill "buf" with MAC address by ifaddrs. Pointer buf must point to a
  139. * buffer with ETHER_ADDR_LEN length at least.
  140. *
  141. * Returns false in case of an error, otherwise true. "obtained" arguument
  142. * is true if a MAC address was obtained successful, otherwise false.
  143. */
  144. bool guest_get_hw_addr(struct ifaddrs *ifa, unsigned char *buf,
  145. bool *obtained, Error **errp)
  146. {
  147. struct sockaddr_dl *sdp;
  148. *obtained = false;
  149. if (ifa->ifa_addr->sa_family != AF_LINK) {
  150. /* We can get HW address only for AF_LINK family. */
  151. g_debug("failed to get MAC address of %s", ifa->ifa_name);
  152. return true;
  153. }
  154. sdp = (struct sockaddr_dl *)ifa->ifa_addr;
  155. memcpy(buf, sdp->sdl_data + sdp->sdl_nlen, ETHER_ADDR_LEN);
  156. *obtained = true;
  157. return true;
  158. }
  159. #endif /* HAVE_GETIFADDRS */