diff --git a/daemon/btrfs.c b/daemon/btrfs.c index 1b76d8c34..6b9397373 100644 --- a/daemon/btrfs.c +++ b/daemon/btrfs.c @@ -1785,3 +1785,147 @@ error: return NULL; } + +guestfs_int_btrfsscrub * +do_btrfs_scrub_status (const char *path) +{ + const size_t MAX_ARGS = 64; + const char *argv[MAX_ARGS]; + size_t i = 0; + CLEANUP_FREE char *path_buf = NULL; + CLEANUP_FREE char *err = NULL; + char *out; + int r; + guestfs_int_btrfsscrub *ret; + char **lines; + + path_buf = sysroot_path (path); + if (path_buf == NULL) { + reply_with_perror ("malloc"); + return NULL; + } + + ADD_ARG (argv, i, str_btrfs); + ADD_ARG (argv, i, "scrub"); + ADD_ARG (argv, i, "status"); + ADD_ARG (argv, i, "-R"); + ADD_ARG (argv, i, path_buf); + ADD_ARG (argv, i, NULL); + + r = commandv (&out, &err, argv); + if (r == -1) { + reply_with_error ("%s: %s", path, err); + return NULL; + } + + if (verbose) + fprintf (stderr, "output from 'btrfs scrub status -R %s' is:\n%s", path, out); + + lines = split_lines (out); + if (!lines) + return NULL; + + if (count_strings (lines) < 2) { + reply_with_error ("truncated output from 'btrfs scrub status -R' command"); + return NULL; + } + + ret = malloc (sizeof *ret); + if (ret == NULL) { + reply_with_perror ("malloc"); + return NULL; + } + memset (ret, 0, sizeof(*ret)); + + /* Output of `btrfs scrub -R status' is like: + * + * scrub status for 346121d1-1847-40f8-9b7b-2bf3d539c68f + * scrub started at Mon Feb 2 17:39:38 2015, running for 93 seconds + * data_extents_scrubbed: 136670 + * tree_extents_scrubbed: 30023 + * data_bytes_scrubbed: 4474441728 + * tree_bytes_scrubbed: 491896832 + * read_errors: 0 + * csum_errors: 0 + * verify_errors: 0 + * no_csum: 17760 + * csum_discards: 197622 + * super_errors: 0 + * malloc_errors: 0 + * uncorrectable_errors: 0 + * unverified_errors: 0 + * corrected_errors: 0 + * last_physical: 10301341696 + * + * or: + * + * scrub status for 346121d1-1847-40f8-9b7b-2bf3d539c68f + * no stats available + */ + for (i = 1; lines[i] != NULL; ++i) { + if ((i == 1) && STREQ (lines[i], "\tno stats available")) + return ret; + else if (STRPREFIX (lines[i], "\tscrub started at")) + continue; + else if (sscanf (lines[i], "\tdata_extents_scrubbed: %" SCNu64, + &ret->btrfsscrub_data_extents_scrubbed) == 1) + continue; + else if (sscanf (lines[i], "\ttree_extents_scrubbed: %" SCNu64, + &ret->btrfsscrub_tree_extents_scrubbed) == 1) + continue; + else if (sscanf (lines[i], "\tdata_bytes_scrubbed: %" SCNu64, + &ret->btrfsscrub_data_bytes_scrubbed) == 1) + continue; + else if (sscanf (lines[i], "\ttree_bytes_scrubbed: %" SCNu64, + &ret->btrfsscrub_tree_bytes_scrubbed) == 1) + continue; + else if (sscanf (lines[i], "\tread_errors: %" SCNu64, + &ret->btrfsscrub_read_errors) == 1) + continue; + else if (sscanf (lines[i], "\tcsum_errors: %" SCNu64, + &ret->btrfsscrub_csum_errors) == 1) + continue; + else if (sscanf (lines[i], "\tverify_errors: %" SCNu64, + &ret->btrfsscrub_verify_errors) == 1) + continue; + else if (sscanf (lines[i], "\tno_csum: %" SCNu64, + &ret->btrfsscrub_no_csum) == 1) + continue; + else if (sscanf (lines[i], "\tcsum_discards: %" SCNu64, + &ret->btrfsscrub_csum_discards) == 1) + continue; + else if (sscanf (lines[i], "\tsuper_errors: %" SCNu64, + &ret->btrfsscrub_super_errors) == 1) + continue; + else if (sscanf (lines[i], "\tmalloc_errors: %" SCNu64, + &ret->btrfsscrub_malloc_errors) == 1) + continue; + else if (sscanf (lines[i], "\tuncorrectable_errors: %" SCNu64, + &ret->btrfsscrub_uncorrectable_errors) == 1) + continue; + else if (sscanf (lines[i], "\tunverified_errors: %" SCNu64, + &ret->btrfsscrub_unverified_errors) == 1) + continue; + else if (sscanf (lines[i], "\tcorrected_errors: %" SCNu64, + &ret->btrfsscrub_corrected_errors) == 1) + continue; + else if (sscanf (lines[i], "\tlast_physical: %" SCNu64, + &ret->btrfsscrub_last_physical) == 1) + continue; + else + goto error; + } + + if (i < 17) { + reply_with_error ("truncated output from 'btrfs scrub status -R' command"); + free (ret); + return NULL; + } + + return ret; + +error: + reply_with_error ("%s: could not parse btrfs scrub status.", lines[i]); + free (ret); + return NULL; +} diff --git a/generator/actions.ml b/generator/actions.ml index 6b13c5d8a..c995787b1 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -12459,6 +12459,22 @@ Return the GUID of numbered GPT partition C." }; longdesc = "\ Show the status of a running or paused balance on a btrfs filesystem." }; + { defaults with + name = "btrfs_scrub_status"; + style = RStruct ("status", "btrfsscrub"), [Pathname "path"], []; + proc_nr = Some 449; + optional = Some "btrfs"; camel_name = "BTRFSScrubStatus"; + tests = [ + InitPartition, Always, TestRun ( + [["mkfs_btrfs"; "/dev/sda1"; ""; ""; "NOARG"; ""; "NOARG"; "NOARG"; ""; ""]; + ["mount"; "/dev/sda1"; "/"]; + ["btrfs_scrub_start"; "/"]; + ["btrfs_scrub_status"; "/"]]), []; + ]; + shortdesc = "show status of running or finished scrub"; + longdesc = "\ +Show status of running or finished scrub on a btrfs filesystem." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/generator/structs.ml b/generator/structs.ml index af42529a3..ea110a12f 100644 --- a/generator/structs.ml +++ b/generator/structs.ml @@ -352,6 +352,28 @@ let structs = [ ]; s_camel_name = "BTRFSBalance" }; + (* btrfs scrub status output *) + { defaults with + s_name = "btrfsscrub"; + s_cols = [ + "btrfsscrub_data_extents_scrubbed", FUInt64; + "btrfsscrub_tree_extents_scrubbed", FUInt64; + "btrfsscrub_data_bytes_scrubbed", FUInt64; + "btrfsscrub_tree_bytes_scrubbed", FUInt64; + "btrfsscrub_read_errors", FUInt64; + "btrfsscrub_csum_errors", FUInt64; + "btrfsscrub_verify_errors", FUInt64; + "btrfsscrub_no_csum", FUInt64; + "btrfsscrub_csum_discards", FUInt64; + "btrfsscrub_super_errors", FUInt64; + "btrfsscrub_malloc_errors", FUInt64; + "btrfsscrub_uncorrectable_errors", FUInt64; + "btrfsscrub_unverified_errors", FUInt64; + "btrfsscrub_corrected_errors", FUInt64; + "btrfsscrub_last_physical", FUInt64; + ]; + s_camel_name = "BTRFSScrub" }; + (* XFS info descriptor. *) { defaults with s_name = "xfsinfo"; diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc index 3ce10f953..6bbd72cee 100644 --- a/gobject/Makefile.inc +++ b/gobject/Makefile.inc @@ -27,6 +27,7 @@ guestfs_gobject_headers= \ include/guestfs-gobject/struct-application2.h \ include/guestfs-gobject/struct-btrfsbalance.h \ include/guestfs-gobject/struct-btrfsqgroup.h \ + include/guestfs-gobject/struct-btrfsscrub.h \ include/guestfs-gobject/struct-btrfssubvolume.h \ include/guestfs-gobject/struct-dirent.h \ include/guestfs-gobject/struct-hivex_node.h \ @@ -111,6 +112,7 @@ guestfs_gobject_sources= \ src/struct-application2.c \ src/struct-btrfsbalance.c \ src/struct-btrfsqgroup.c \ + src/struct-btrfsscrub.c \ src/struct-btrfssubvolume.c \ src/struct-dirent.c \ src/struct-hivex_node.c \ diff --git a/java/Makefile.inc b/java/Makefile.inc index 499d3deb8..477842a26 100644 --- a/java/Makefile.inc +++ b/java/Makefile.inc @@ -24,6 +24,7 @@ java_built_sources = \ com/redhat/et/libguestfs/Application2.java \ com/redhat/et/libguestfs/BTRFSBalance.java \ com/redhat/et/libguestfs/BTRFSQgroup.java \ + com/redhat/et/libguestfs/BTRFSScrub.java \ com/redhat/et/libguestfs/BTRFSSubvolume.java \ com/redhat/et/libguestfs/Dirent.java \ com/redhat/et/libguestfs/HivexNode.java \ diff --git a/java/com/redhat/et/libguestfs/.gitignore b/java/com/redhat/et/libguestfs/.gitignore index b2b1b2220..83892691f 100644 --- a/java/com/redhat/et/libguestfs/.gitignore +++ b/java/com/redhat/et/libguestfs/.gitignore @@ -2,6 +2,7 @@ Application.java Application2.java BTRFSBalance.java BTRFSQgroup.java +BTRFSScrub.java BTRFSSubvolume.java Dirent.java HivexNode.java diff --git a/po/POTFILES b/po/POTFILES index 3f66c9ffe..f1c42fe3c 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -232,6 +232,7 @@ gobject/src/struct-application.c gobject/src/struct-application2.c gobject/src/struct-btrfsbalance.c gobject/src/struct-btrfsqgroup.c +gobject/src/struct-btrfsscrub.c gobject/src/struct-btrfssubvolume.c gobject/src/struct-dirent.c gobject/src/struct-hivex_node.c diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 5379c470d..2b20fd097 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -448 +449