commands-posix.c (518b0d800b5ab046b72fac423ace7549ab187329) commands-posix.c (bad0001eeb34484c4595c3862e14a4ee22a3abee)
1/*
2 * QEMU Guest Agent POSIX-specific command implementations
3 *
4 * Copyright IBM Corp. 2011
5 *
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
8 * Michal Privoznik <mprivozn@redhat.com>

--- 19 unchanged lines hidden (view full) ---

28#include "cutils.h"
29
30#ifdef HAVE_UTMPX
31#include <utmpx.h>
32#endif
33
34#if defined(__linux__)
35#include <mntent.h>
1/*
2 * QEMU Guest Agent POSIX-specific command implementations
3 *
4 * Copyright IBM Corp. 2011
5 *
6 * Authors:
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
8 * Michal Privoznik <mprivozn@redhat.com>

--- 19 unchanged lines hidden (view full) ---

28#include "cutils.h"
29
30#ifdef HAVE_UTMPX
31#include <utmpx.h>
32#endif
33
34#if defined(__linux__)
35#include <mntent.h>
36#include <linux/fs.h>
37#include <sys/statvfs.h>
38#include <linux/nvme_ioctl.h>
39
40#ifdef CONFIG_LIBUDEV
41#include <libudev.h>
42#endif
36#include <sys/statvfs.h>
37#include <linux/nvme_ioctl.h>
38
39#ifdef CONFIG_LIBUDEV
40#include <libudev.h>
41#endif
43
44#ifdef FIFREEZE
45#define CONFIG_FSFREEZE
46#endif
42#endif
47#ifdef FITRIM
48#define CONFIG_FSTRIM
49#endif
50#endif
51
52#ifdef __FreeBSD__
53/*
54 * The code under HAVE_GETIFADDRS condition can't be compiled in FreeBSD.
55 * Fix it in one of the following patches.
56 */
57#undef HAVE_GETIFADDRS
58#endif

--- 559 unchanged lines hidden (view full) ---

618 ret = fflush(fh);
619 if (ret == EOF) {
620 error_setg_errno(errp, errno, "failed to flush file");
621 } else {
622 gfh->state = RW_STATE_NEW;
623 }
624}
625
43
44#ifdef __FreeBSD__
45/*
46 * The code under HAVE_GETIFADDRS condition can't be compiled in FreeBSD.
47 * Fix it in one of the following patches.
48 */
49#undef HAVE_GETIFADDRS
50#endif

--- 559 unchanged lines hidden (view full) ---

610 ret = fflush(fh);
611 if (ret == EOF) {
612 error_setg_errno(errp, errno, "failed to flush file");
613 } else {
614 gfh->state = RW_STATE_NEW;
615 }
616}
617
626/* linux-specific implementations. avoid this if at all possible. */
627#if defined(__linux__)
628
629#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
630void free_fs_mount_list(FsMountList *mounts)
631{
632 FsMount *mount, *temp;
633
634 if (!mounts) {
635 return;
636 }
637
638 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
639 QTAILQ_REMOVE(mounts, mount, next);
640 g_free(mount->dirname);
641 g_free(mount->devtype);
642 g_free(mount);
643 }
644}
645#endif
646
647#if defined(CONFIG_FSFREEZE)
618#if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
619void free_fs_mount_list(FsMountList *mounts)
620{
621 FsMount *mount, *temp;
622
623 if (!mounts) {
624 return;
625 }
626
627 QTAILQ_FOREACH_SAFE(mount, mounts, next, temp) {
628 QTAILQ_REMOVE(mounts, mount, next);
629 g_free(mount->dirname);
630 g_free(mount->devtype);
631 g_free(mount);
632 }
633}
634#endif
635
636#if defined(CONFIG_FSFREEZE)
637typedef enum {
638 FSFREEZE_HOOK_THAW = 0,
639 FSFREEZE_HOOK_FREEZE,
640} FsfreezeHookArg;
648
641
642static const char *fsfreeze_hook_arg_string[] = {
643 "thaw",
644 "freeze",
645};
646
647static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp)
648{
649 int status;
650 pid_t pid;
651 const char *hook;
652 const char *arg_str = fsfreeze_hook_arg_string[arg];
653 Error *local_err = NULL;
654
655 hook = ga_fsfreeze_hook(ga_state);
656 if (!hook) {
657 return;
658 }
659 if (access(hook, X_OK) != 0) {
660 error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook);
661 return;
662 }
663
664 slog("executing fsfreeze hook with arg '%s'", arg_str);
665 pid = fork();
666 if (pid == 0) {
667 setsid();
668 reopen_fd_to_null(0);
669 reopen_fd_to_null(1);
670 reopen_fd_to_null(2);
671
672 execl(hook, hook, arg_str, NULL);
673 _exit(EXIT_FAILURE);
674 } else if (pid < 0) {
675 error_setg_errno(errp, errno, "failed to create child process");
676 return;
677 }
678
679 ga_wait_child(pid, &status, &local_err);
680 if (local_err) {
681 error_propagate(errp, local_err);
682 return;
683 }
684
685 if (!WIFEXITED(status)) {
686 error_setg(errp, "fsfreeze hook has terminated abnormally");
687 return;
688 }
689
690 status = WEXITSTATUS(status);
691 if (status) {
692 error_setg(errp, "fsfreeze hook has failed with status %d", status);
693 return;
694 }
695}
696
697/*
698 * Return status of freeze/thaw
699 */
700GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
701{
702 if (ga_is_frozen(ga_state)) {
703 return GUEST_FSFREEZE_STATUS_FROZEN;
704 }
705
706 return GUEST_FSFREEZE_STATUS_THAWED;
707}
708
709int64_t qmp_guest_fsfreeze_freeze(Error **errp)
710{
711 return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
712}
713
714int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
715 strList *mountpoints,
716 Error **errp)
717{
718 int ret;
719 FsMountList mounts;
720 Error *local_err = NULL;
721
722 slog("guest-fsfreeze called");
723
724 execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
725 if (local_err) {
726 error_propagate(errp, local_err);
727 return -1;
728 }
729
730 QTAILQ_INIT(&mounts);
731 if (!build_fs_mount_list(&mounts, &local_err)) {
732 error_propagate(errp, local_err);
733 return -1;
734 }
735
736 /* cannot risk guest agent blocking itself on a write in this state */
737 ga_set_frozen(ga_state);
738
739 ret = qmp_guest_fsfreeze_do_freeze_list(has_mountpoints, mountpoints,
740 mounts, errp);
741
742 free_fs_mount_list(&mounts);
743 /* We may not issue any FIFREEZE here.
744 * Just unset ga_state here and ready for the next call.
745 */
746 if (ret == 0) {
747 ga_unset_frozen(ga_state);
748 } else if (ret < 0) {
749 qmp_guest_fsfreeze_thaw(NULL);
750 }
751 return ret;
752}
753
754int64_t qmp_guest_fsfreeze_thaw(Error **errp)
755{
756 int ret;
757
758 ret = qmp_guest_fsfreeze_do_thaw(errp);
759 if (ret >= 0) {
760 ga_unset_frozen(ga_state);
761 execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp);
762 } else {
763 ret = 0;
764 }
765
766 return ret;
767}
768
769static void guest_fsfreeze_cleanup(void)
770{
771 Error *err = NULL;
772
773 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
774 qmp_guest_fsfreeze_thaw(&err);
775 if (err) {
776 slog("failed to clean up frozen filesystems: %s",
777 error_get_pretty(err));
778 error_free(err);
779 }
780 }
781}
782#endif
783
784/* linux-specific implementations. avoid this if at all possible. */
785#if defined(__linux__)
786#if defined(CONFIG_FSFREEZE)
787
649static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
650{
651 char *path;
652 char *dpath;
653 char *driver = NULL;
654 char buf[PATH_MAX];
655 ssize_t len;
656

--- 805 unchanged lines hidden (view full) ---

1462 ret = NULL;
1463 break;
1464 }
1465 }
1466
1467 free_fs_mount_list(&mounts);
1468 return ret;
1469}
788static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
789{
790 char *path;
791 char *dpath;
792 char *driver = NULL;
793 char buf[PATH_MAX];
794 ssize_t len;
795

--- 805 unchanged lines hidden (view full) ---

1601 ret = NULL;
1602 break;
1603 }
1604 }
1605
1606 free_fs_mount_list(&mounts);
1607 return ret;
1608}
1470
1471
1472typedef enum {
1473 FSFREEZE_HOOK_THAW = 0,
1474 FSFREEZE_HOOK_FREEZE,
1475} FsfreezeHookArg;
1476
1477static const char *fsfreeze_hook_arg_string[] = {
1478 "thaw",
1479 "freeze",
1480};
1481
1482static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **errp)
1483{
1484 int status;
1485 pid_t pid;
1486 const char *hook;
1487 const char *arg_str = fsfreeze_hook_arg_string[arg];
1488 Error *local_err = NULL;
1489
1490 hook = ga_fsfreeze_hook(ga_state);
1491 if (!hook) {
1492 return;
1493 }
1494 if (access(hook, X_OK) != 0) {
1495 error_setg_errno(errp, errno, "can't access fsfreeze hook '%s'", hook);
1496 return;
1497 }
1498
1499 slog("executing fsfreeze hook with arg '%s'", arg_str);
1500 pid = fork();
1501 if (pid == 0) {
1502 setsid();
1503 reopen_fd_to_null(0);
1504 reopen_fd_to_null(1);
1505 reopen_fd_to_null(2);
1506
1507 execl(hook, hook, arg_str, NULL);
1508 _exit(EXIT_FAILURE);
1509 } else if (pid < 0) {
1510 error_setg_errno(errp, errno, "failed to create child process");
1511 return;
1512 }
1513
1514 ga_wait_child(pid, &status, &local_err);
1515 if (local_err) {
1516 error_propagate(errp, local_err);
1517 return;
1518 }
1519
1520 if (!WIFEXITED(status)) {
1521 error_setg(errp, "fsfreeze hook has terminated abnormally");
1522 return;
1523 }
1524
1525 status = WEXITSTATUS(status);
1526 if (status) {
1527 error_setg(errp, "fsfreeze hook has failed with status %d", status);
1528 return;
1529 }
1530}
1531
1532/*
1533 * Return status of freeze/thaw
1534 */
1535GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
1536{
1537 if (ga_is_frozen(ga_state)) {
1538 return GUEST_FSFREEZE_STATUS_FROZEN;
1539 }
1540
1541 return GUEST_FSFREEZE_STATUS_THAWED;
1542}
1543
1544int64_t qmp_guest_fsfreeze_freeze(Error **errp)
1545{
1546 return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
1547}
1548
1549int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
1550 strList *mountpoints,
1551 Error **errp)
1552{
1553 int ret;
1554 FsMountList mounts;
1555 Error *local_err = NULL;
1556
1557 slog("guest-fsfreeze called");
1558
1559 execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
1560 if (local_err) {
1561 error_propagate(errp, local_err);
1562 return -1;
1563 }
1564
1565 QTAILQ_INIT(&mounts);
1566 if (!build_fs_mount_list(&mounts, &local_err)) {
1567 error_propagate(errp, local_err);
1568 return -1;
1569 }
1570
1571 /* cannot risk guest agent blocking itself on a write in this state */
1572 ga_set_frozen(ga_state);
1573
1574 ret = qmp_guest_fsfreeze_do_freeze_list(has_mountpoints, mountpoints,
1575 mounts, errp);
1576
1577 free_fs_mount_list(&mounts);
1578 /* We may not issue any FIFREEZE here.
1579 * Just unset ga_state here and ready for the next call.
1580 */
1581 if (ret == 0) {
1582 ga_unset_frozen(ga_state);
1583 } else if (ret < 0) {
1584 qmp_guest_fsfreeze_thaw(NULL);
1585 }
1586 return ret;
1587}
1588
1589int64_t qmp_guest_fsfreeze_thaw(Error **errp)
1590{
1591 int ret;
1592
1593 ret = qmp_guest_fsfreeze_do_thaw(errp);
1594 if (ret >= 0) {
1595 ga_unset_frozen(ga_state);
1596 execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp);
1597 } else {
1598 ret = 0;
1599 }
1600
1601 return ret;
1602}
1603
1604static void guest_fsfreeze_cleanup(void)
1605{
1606 Error *err = NULL;
1607
1608 if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
1609 qmp_guest_fsfreeze_thaw(&err);
1610 if (err) {
1611 slog("failed to clean up frozen filesystems: %s",
1612 error_get_pretty(err));
1613 error_free(err);
1614 }
1615 }
1616}
1617#endif /* CONFIG_FSFREEZE */
1618
1619#if defined(CONFIG_FSTRIM)
1620/*
1621 * Walk list of mounted file systems in the guest, and trim them.
1622 */
1623GuestFilesystemTrimResponse *
1624qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)

--- 1785 unchanged lines hidden ---
1609#endif /* CONFIG_FSFREEZE */
1610
1611#if defined(CONFIG_FSTRIM)
1612/*
1613 * Walk list of mounted file systems in the guest, and trim them.
1614 */
1615GuestFilesystemTrimResponse *
1616qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)

--- 1785 unchanged lines hidden ---