Commit f7b4a940a430da0e2d48b74e85a8a941c1c2fabc
1 parent
fa879c64
snapshot subcommand for qemu-img (Kevin Wolf)
Add snapshot subcommand to qemu-img which allows to list, create, apply and delete snapshots on qcow2 images. Signed-off-by: Kevin Wolf <kwolf@suse.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6215 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
125 additions
and
0 deletions
osdep.h
qemu-img.c
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | * THE SOFTWARE. |
23 | 23 | */ |
24 | 24 | #include "qemu-common.h" |
25 | +#include "osdep.h" | |
25 | 26 | #include "block_int.h" |
26 | 27 | #include <assert.h> |
27 | 28 | |
... | ... | @@ -60,6 +61,7 @@ static void help(void) |
60 | 61 | " commit [-f fmt] filename\n" |
61 | 62 | " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" |
62 | 63 | " info [-f fmt] filename\n" |
64 | + " snapshot [-l|-a snapshot|-c snapshot|-d snapshot] filename\n" | |
63 | 65 | "\n" |
64 | 66 | "Command parameters:\n" |
65 | 67 | " 'filename' is a disk image filename\n" |
... | ... | @@ -77,6 +79,13 @@ static void help(void) |
77 | 79 | " '-c' indicates that target image must be compressed (qcow format only)\n" |
78 | 80 | " '-e' indicates that the target image must be encrypted (qcow format only)\n" |
79 | 81 | " '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n" |
82 | + "\n" | |
83 | + " Parameters to snapshot subcommand:\n" | |
84 | + " 'snapshot' is the name of the snapshot to create, apply or delete\n" | |
85 | + " '-a' applies a snapshot (revert disk to saved state)\n" | |
86 | + " '-c' creates a snapshot\n" | |
87 | + " '-d' deletes a snapshot\n" | |
88 | + " '-l' lists all snapshots in the given image\n" | |
80 | 89 | ); |
81 | 90 | printf("\nSupported format:"); |
82 | 91 | bdrv_iterate_format(format_print, NULL); |
... | ... | @@ -732,6 +741,116 @@ static int img_info(int argc, char **argv) |
732 | 741 | return 0; |
733 | 742 | } |
734 | 743 | |
744 | +#define SNAPSHOT_LIST 1 | |
745 | +#define SNAPSHOT_CREATE 2 | |
746 | +#define SNAPSHOT_APPLY 3 | |
747 | +#define SNAPSHOT_DELETE 4 | |
748 | + | |
749 | +static void img_snapshot(int argc, char **argv) | |
750 | +{ | |
751 | + BlockDriverState *bs; | |
752 | + QEMUSnapshotInfo sn; | |
753 | + char *filename, *snapshot_name = NULL; | |
754 | + char c; | |
755 | + int ret; | |
756 | + int action = 0; | |
757 | + qemu_timeval tv; | |
758 | + | |
759 | + /* Parse commandline parameters */ | |
760 | + for(;;) { | |
761 | + c = getopt(argc, argv, "la:c:d:h"); | |
762 | + if (c == -1) | |
763 | + break; | |
764 | + switch(c) { | |
765 | + case 'h': | |
766 | + help(); | |
767 | + return; | |
768 | + case 'l': | |
769 | + if (action) { | |
770 | + help(); | |
771 | + return; | |
772 | + } | |
773 | + action = SNAPSHOT_LIST; | |
774 | + break; | |
775 | + case 'a': | |
776 | + if (action) { | |
777 | + help(); | |
778 | + return; | |
779 | + } | |
780 | + action = SNAPSHOT_APPLY; | |
781 | + snapshot_name = optarg; | |
782 | + break; | |
783 | + case 'c': | |
784 | + if (action) { | |
785 | + help(); | |
786 | + return; | |
787 | + } | |
788 | + action = SNAPSHOT_CREATE; | |
789 | + snapshot_name = optarg; | |
790 | + break; | |
791 | + case 'd': | |
792 | + if (action) { | |
793 | + help(); | |
794 | + return; | |
795 | + } | |
796 | + action = SNAPSHOT_DELETE; | |
797 | + snapshot_name = optarg; | |
798 | + break; | |
799 | + } | |
800 | + } | |
801 | + | |
802 | + if (optind >= argc) | |
803 | + help(); | |
804 | + filename = argv[optind++]; | |
805 | + | |
806 | + /* Open the image */ | |
807 | + bs = bdrv_new(""); | |
808 | + if (!bs) | |
809 | + error("Not enough memory"); | |
810 | + | |
811 | + if (bdrv_open2(bs, filename, 0, NULL) < 0) { | |
812 | + error("Could not open '%s'", filename); | |
813 | + } | |
814 | + | |
815 | + /* Perform the requested action */ | |
816 | + switch(action) { | |
817 | + case SNAPSHOT_LIST: | |
818 | + dump_snapshots(bs); | |
819 | + break; | |
820 | + | |
821 | + case SNAPSHOT_CREATE: | |
822 | + memset(&sn, 0, sizeof(sn)); | |
823 | + pstrcpy(sn.name, sizeof(sn.name), snapshot_name); | |
824 | + | |
825 | + qemu_gettimeofday(&tv); | |
826 | + sn.date_sec = tv.tv_sec; | |
827 | + sn.date_nsec = tv.tv_usec * 1000; | |
828 | + | |
829 | + ret = bdrv_snapshot_create(bs, &sn); | |
830 | + if (ret) | |
831 | + error("Could not create snapshot '%s': %d (%s)", | |
832 | + snapshot_name, ret, strerror(-ret)); | |
833 | + break; | |
834 | + | |
835 | + case SNAPSHOT_APPLY: | |
836 | + ret = bdrv_snapshot_goto(bs, snapshot_name); | |
837 | + if (ret) | |
838 | + error("Could not apply snapshot '%s': %d (%s)", | |
839 | + snapshot_name, ret, strerror(-ret)); | |
840 | + break; | |
841 | + | |
842 | + case SNAPSHOT_DELETE: | |
843 | + ret = bdrv_snapshot_delete(bs, snapshot_name); | |
844 | + if (ret) | |
845 | + error("Could not delete snapshot '%s': %d (%s)", | |
846 | + snapshot_name, ret, strerror(-ret)); | |
847 | + break; | |
848 | + } | |
849 | + | |
850 | + /* Cleanup */ | |
851 | + bdrv_delete(bs); | |
852 | +} | |
853 | + | |
735 | 854 | int main(int argc, char **argv) |
736 | 855 | { |
737 | 856 | const char *cmd; |
... | ... | @@ -749,6 +868,8 @@ int main(int argc, char **argv) |
749 | 868 | img_convert(argc, argv); |
750 | 869 | } else if (!strcmp(cmd, "info")) { |
751 | 870 | img_info(argc, argv); |
871 | + } else if (!strcmp(cmd, "snapshot")) { | |
872 | + img_snapshot(argc, argv); | |
752 | 873 | } else { |
753 | 874 | help(); |
754 | 875 | } | ... | ... |