diff --git a/RHEL-132202-1-gfs2_edit_Use_0x_notation_when_printing_hexadecimal_values.patch b/RHEL-132202-1-gfs2_edit_Use_0x_notation_when_printing_hexadecimal_values.patch new file mode 100644 index 0000000..50fa68e --- /dev/null +++ b/RHEL-132202-1-gfs2_edit_Use_0x_notation_when_printing_hexadecimal_values.patch @@ -0,0 +1,45 @@ +commit 83ded388446e7422715196b2f470f1169d130311 +Author: Andrew Price +Date: Mon Dec 1 14:39:30 2025 +0000 + + gfs2_edit: Use 0x notation when printing hexadecimal values + + Changes the output of gfs2_edit -x for struct fields and log header + flags. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c +index 5d8811a6..82f5d3a8 100644 +--- a/gfs2/libgfs2/meta.c ++++ b/gfs2/libgfs2/meta.c +@@ -887,7 +887,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct + } + + if (hex) { +- snprintf(str, size, "%"PRIx64, value); ++ snprintf(str, size, "0x%"PRIx64, value); + goto out; + } + if (field->flags & LGFS2_MFF_MASK) { +diff --git a/tests/mkfs.at b/tests/mkfs.at +index 7064a9e2..9c93c80f 100644 +--- a/tests/mkfs.at ++++ b/tests/mkfs.at +@@ -206,11 +206,11 @@ AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata= $GFS_TGT], 255, [ignor + AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=42 $GFS_TGT], 255, [ignore], [ignore]) + AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=X $GFS_TGT], 255, [ignore], [ignore]) + AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata $GFS_TGT], 0, [ignore], [ignore]) +-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [80000001], [ignore]) ++AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x80000001], [ignore]) + AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=1 $GFS_TGT], 0, [ignore], [ignore]) +-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [80000001], [ignore]) ++AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x80000001], [ignore]) + AT_CHECK([$GFS_MKFS -p lock_nolock -o root_inherit_jdata=0 $GFS_TGT], 0, [ignore], [ignore]) +-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [1], [ignore]) ++AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x1], [ignore]) + AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) +-AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [1], [ignore]) ++AT_CHECK([gfs2_edit -x -p root field di_flags $GFS_TGT | tr -d '\n'], 0, [0x1], [ignore]) + AT_CLEANUP diff --git a/RHEL-132202-2-libgfs2_Add_a_function_to_look_up_flags_by_symbol.patch b/RHEL-132202-2-libgfs2_Add_a_function_to_look_up_flags_by_symbol.patch new file mode 100644 index 0000000..b6b72d6 --- /dev/null +++ b/RHEL-132202-2-libgfs2_Add_a_function_to_look_up_flags_by_symbol.patch @@ -0,0 +1,98 @@ +commit 9179cb0f0bec09add0b64281bcd917e1869e3569 +Author: Andrew Price +Date: Mon Dec 1 15:51:54 2025 +0000 + + libgfs2: Add a function to look up flags by symbol + + Add lgfs2_flag_sym_value() to simplify parsing of flag values from + strings. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/libgfs2/check_meta.c b/gfs2/libgfs2/check_meta.c +index 340d3c8d..8e448203 100644 +--- a/gfs2/libgfs2/check_meta.c ++++ b/gfs2/libgfs2/check_meta.c +@@ -38,6 +38,30 @@ START_TEST(check_symtab) + } + END_TEST + ++START_TEST(check_flag_sym_value) ++{ ++ const struct lgfs2_metadata *di_meta = &lgfs2_metadata[LGFS2_MT_GFS2_DINODE]; ++ const struct lgfs2_metafield *flags_field = lgfs2_find_mfield_name("di_flags", di_meta); ++ ++ ck_assert(lgfs2_flag_sym_value(NULL, flags_field) == 0); ++ ck_assert(lgfs2_flag_sym_value("", flags_field) == 0); ++ ck_assert(lgfs2_flag_sym_value("invalid_flag", flags_field) == 0); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_JDATA", flags_field) == GFS2_DIF_JDATA); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_EXHASH", flags_field) == GFS2_DIF_EXHASH); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_UNUSED", flags_field) == GFS2_DIF_UNUSED); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_EA_INDIRECT", flags_field) == GFS2_DIF_EA_INDIRECT); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_DIRECTIO", flags_field) == GFS2_DIF_DIRECTIO); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_IMMUTABLE", flags_field) == GFS2_DIF_IMMUTABLE); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_APPENDONLY", flags_field) == GFS2_DIF_APPENDONLY); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_NOATIME", flags_field) == GFS2_DIF_NOATIME); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_SYNC", flags_field) == GFS2_DIF_SYNC); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_SYSTEM", flags_field) == GFS2_DIF_SYSTEM); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_TRUNC_IN_PROG", flags_field) == GFS2_DIF_TRUNC_IN_PROG); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_INHERIT_DIRECTIO", flags_field) == GFS2_DIF_INHERIT_DIRECTIO); ++ ck_assert(lgfs2_flag_sym_value("GFS2_DIF_INHERIT_JDATA", flags_field) == GFS2_DIF_INHERIT_JDATA); ++} ++END_TEST ++ + START_TEST(check_ptrs) + { + int i, j; +@@ -64,6 +88,7 @@ Suite *suite_meta(void) + tcase_add_test(tc_meta, check_metadata_sizes); + tcase_add_test(tc_meta, check_symtab); + tcase_add_test(tc_meta, check_ptrs); ++ tcase_add_test(tc_meta, check_flag_sym_value); + suite_add_tcase(s, tc_meta); + + return s; +diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h +index 7531a2d6..abe9944e 100644 +--- a/gfs2/libgfs2/libgfs2.h ++++ b/gfs2/libgfs2/libgfs2.h +@@ -452,6 +452,7 @@ extern const struct lgfs2_metadata *lgfs2_find_mtype(uint32_t mh_type, const uns + extern const struct lgfs2_metadata *lgfs2_find_mtype_name(const char *name, const unsigned versions); + extern const struct lgfs2_metafield *lgfs2_find_mfield_name(const char *name, const struct lgfs2_metadata *mtype); + extern int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct lgfs2_metafield *field, int hex); ++extern uint32_t lgfs2_flag_sym_value(const char *sym, const struct lgfs2_metafield *field); + extern int lgfs2_field_assign(char *blk, const struct lgfs2_metafield *field, const void *val); + + /* buf.c */ +diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c +index 82f5d3a8..3b313ad2 100644 +--- a/gfs2/libgfs2/meta.c ++++ b/gfs2/libgfs2/meta.c +@@ -922,6 +922,26 @@ out: + return 0; + } + ++/** ++ * Look up a flag value from a symbolic name. Matching is case-sensitive. ++ * Does not parse combined symbols like "X|Y". ++ * sym: the symbolic name ++ * field: the flags field the name relates to. ++ * Returns the flag value or 0 if not found. ++ */ ++uint32_t lgfs2_flag_sym_value(const char *sym, const struct lgfs2_metafield *field) ++{ ++ if (sym == NULL) ++ return 0; ++ ++ for (unsigned i = 0; i < field->nsyms; i++) ++ { ++ if (strcmp(sym, field->symtab[i].value) == 0) ++ return field->symtab[i].key; ++ } ++ return 0; ++} ++ + int lgfs2_field_assign(char *blk, const struct lgfs2_metafield *field, const void *val) + { + char *fieldp = blk + field->offset; diff --git a/RHEL-132202-3-gfs2_edit_Allow_setting_flags_fields_using_symbols.patch b/RHEL-132202-3-gfs2_edit_Allow_setting_flags_fields_using_symbols.patch new file mode 100644 index 0000000..8d295fe --- /dev/null +++ b/RHEL-132202-3-gfs2_edit_Allow_setting_flags_fields_using_symbols.patch @@ -0,0 +1,95 @@ +commit 67b9d9a2f1380a8db1bcb963b18cdd00550c76b9 +Author: Andrew Price +Date: Mon Dec 1 19:30:29 2025 +0000 + + gfs2_edit: Allow setting flags fields using symbols + + Parse combinations of symbolic flags to set flags fields. + + The separator is chosen to be '|' as it's consistent with C. It has the + drawback of needing to be escaped in command lines but unfortunately the + argument parsing code treats anything with '/' as a path so the + separator used in output cannot be used. Adding a third separator would + be even more confusing. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c +index ccce0fd0..821b9a02 100644 +--- a/gfs2/edit/hexedit.c ++++ b/gfs2/edit/hexedit.c +@@ -1689,6 +1689,38 @@ static void find_change_block_alloc(int *newval) + exit(0); + } + ++/** ++ * Parse a string like "GFS2_DIF_SYSTEM|GFS2_DIF_JDATA" into the corresponding ++ * value for a bitmask field. ++ * syms: The string. ++ * field: The field type. ++ * Returns the values for the specified flags ORed together or 0 on failure. ++ */ ++static uint32_t flag_syms_value(const char *syms, const struct lgfs2_metafield *field) ++{ ++ char *str, *iter, *tok; ++ uint32_t val = 0; ++ ++ if (syms == NULL || *syms == '\0') ++ return 0; ++ ++ str = iter = strdup(syms); ++ if (str == NULL) ++ return 0; ++ ++ while ((tok = strsep(&iter, "|"))) { ++ uint32_t flag = lgfs2_flag_sym_value(tok, field); ++ ++ if (flag == 0) { ++ free(str); ++ return 0; ++ } ++ val |= flag; ++ } ++ free(str); ++ return val; ++} ++ + /** + * process request to print a certain field from a previously pushed block + */ +@@ -1720,7 +1752,13 @@ static void process_field(const char *field, const char *nstr) + err = lgfs2_field_assign(rbh->b_data, mfield, nstr); + } else { + uint64_t val = 0; +- err = sscanf(nstr, "%"SCNi64, &val); ++ ++ if (mfield->flags & LGFS2_MFF_MASK) { ++ val = flag_syms_value(nstr, mfield); ++ err = 1; ++ } ++ if (val == 0) ++ err = sscanf(nstr, "%"SCNi64, &val); + if (err == 1) + /* coverity[overrun-buffer-val:SUPPRESS] False positive */ + err = lgfs2_field_assign(rbh->b_data, mfield, &val); +diff --git a/tests/edit.at b/tests/edit.at +index 29835df0..bc3dc28b 100644 +--- a/tests/edit.at ++++ b/tests/edit.at +@@ -71,3 +71,15 @@ AT_CHECK([truncate -s 10K test.file], 0, [ignore], [ignore]) + AT_CHECK([gfs2_edit restoremeta test.meta test.file], 0, [ignore], [ignore]) + AT_CHECK([fsck.gfs2 -n test.file], 0, [ignore], [ignore]) + AT_CLEANUP ++ ++AT_SETUP([Set flags by symbol]) ++AT_KEYWORDS(gfs2_edit edit) ++GFS_TGT_REGEN ++AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([gfs2_edit -p journal0 field di_flags invalid_flag $GFS_TGT], 1, [ignore], [ignore]) ++AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_SYSTEM], [ignore]) ++AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore]) ++AT_CHECK([gfs2_edit -x -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore]) ++AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore]) ++AT_CHECK([gfs2_edit -x -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore]) ++AT_CLEANUP diff --git a/RHEL-132202-4-gfs2_edit_Only_call_ioctl_BLKFLSBUF_on_block_devices.patch b/RHEL-132202-4-gfs2_edit_Only_call_ioctl_BLKFLSBUF_on_block_devices.patch new file mode 100644 index 0000000..7e0fb05 --- /dev/null +++ b/RHEL-132202-4-gfs2_edit_Only_call_ioctl_BLKFLSBUF_on_block_devices.patch @@ -0,0 +1,65 @@ +commit 45628f23874fb8f596f5e8368f4247f08b30703b +Author: Andrew Price +Date: Tue Dec 2 14:25:03 2025 +0000 + + gfs2_edit: Only call ioctl(BLKFLSBUF) on block devices + + Prevents failures of these calls causing confusing error messages. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c +index 821b9a02..7e3a8a24 100644 +--- a/gfs2/edit/hexedit.c ++++ b/gfs2/edit/hexedit.c +@@ -42,6 +42,7 @@ static struct lgfs2_inum gfs1_license_di; + + int details = 0; + char *device = NULL; ++struct stat devstat; + + /* ------------------------------------------------------------------------- */ + /* erase - clear the screen */ +@@ -872,7 +873,8 @@ static void read_superblock(int fd) + { + struct gfs2_meta_header *mh; + +- ioctl(fd, BLKFLSBUF, 0); ++ if (S_ISBLK(devstat.st_mode)) ++ ioctl(fd, BLKFLSBUF, 0); + memset(&sbd, 0, sizeof(struct lgfs2_sbd)); + sbd.sd_bsize = LGFS2_DEFAULT_BSIZE; + sbd.device_fd = fd; +@@ -950,7 +952,8 @@ static int read_rindex(void) + + static int read_master_dir(void) + { +- ioctl(sbd.device_fd, BLKFLSBUF, 0); ++ if (S_ISBLK(devstat.st_mode)) ++ ioctl(sbd.device_fd, BLKFLSBUF, 0); + + bh = lgfs2_bread(&sbd, sbd.sd_meta_dir.in_addr); + if (bh == NULL) +@@ -986,7 +989,8 @@ int display(int identify_only, int trunc_zeros, uint64_t flagref, + if (bh != NULL) + lgfs2_brelse(bh); + dev_offset = blk * sbd.sd_bsize; +- ioctl(sbd.device_fd, BLKFLSBUF, 0); ++ if (S_ISBLK(devstat.st_mode)) ++ ioctl(sbd.device_fd, BLKFLSBUF, 0); + if (!(bh = lgfs2_bread(&sbd, blk))) { + fprintf(stderr, "read error: %s from %s:%d: " + "offset %"PRIu64" (0x%"PRIx64")\n", +@@ -2575,6 +2579,11 @@ int main(int argc, char *argv[]) + fprintf(stderr, "Failed to open '%s': %s\n", device, strerror(errno)); + exit(1); + } ++ if (fstat(fd, &devstat) != 0) { ++ fprintf(stderr, "Failed to fstat '%s': %s\n", device, strerror(errno)); ++ close(fd); ++ exit(1); ++ } + max_block = lseek(fd, 0, SEEK_END) / sbd.sd_bsize; + + read_superblock(fd); diff --git a/RHEL-132202-5-libgfs2_Fall_back_to_printing_a_numerical_value_in_lgfs2_field_str.patch b/RHEL-132202-5-libgfs2_Fall_back_to_printing_a_numerical_value_in_lgfs2_field_str.patch new file mode 100644 index 0000000..24c7f7e --- /dev/null +++ b/RHEL-132202-5-libgfs2_Fall_back_to_printing_a_numerical_value_in_lgfs2_field_str.patch @@ -0,0 +1,60 @@ +commit 18fcae907955e5d24ddd63c9f98aa28c2e92ab5c +Author: Andrew Price +Date: Tue Dec 2 17:06:31 2025 +0000 + + libgfs2: Fall back to printing a numerical value in lgfs2_field_str() + + If the bitmask value isn't a valid combination of flags then + lgfs2_field_str() currently leaves the resulting string empty. Fall back + to setting the string to the numerical value instead. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c +index 3b313ad2..8b93c0a0 100644 +--- a/gfs2/libgfs2/meta.c ++++ b/gfs2/libgfs2/meta.c +@@ -1,4 +1,5 @@ + #include ++#include + #include + #include + #include "libgfs2.h" +@@ -892,6 +893,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct + } + if (field->flags & LGFS2_MFF_MASK) { + char *s = str, *end = str + size; ++ bool found = false; + unsigned n; + + for (n = 0; n < field->nsyms; n++) { +@@ -899,6 +901,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct + + if (!(value & sym->key)) + continue; ++ found = true; + if (s != str && s < end) + *s++ = '/'; + if (s < end) { +@@ -913,7 +916,8 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct + } + if (s < end) + *s = '\0'; +- goto out; ++ if (found) ++ goto out; + } + snprintf(str, size, "%"PRIu64, value); + } +diff --git a/tests/edit.at b/tests/edit.at +index bc3dc28b..22a60f04 100644 +--- a/tests/edit.at ++++ b/tests/edit.at +@@ -82,4 +82,6 @@ AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' + AT_CHECK([gfs2_edit -x -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore]) + AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore]) + AT_CHECK([gfs2_edit -x -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore]) ++AT_CHECK([gfs2_edit -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0], [ignore]) ++AT_CHECK([gfs2_edit -x -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0x0], [ignore]) + AT_CLEANUP diff --git a/RHEL-132202-6-gfs2_edit_Set_errno_for_invalid_flag_arguments_in_process_field.patch b/RHEL-132202-6-gfs2_edit_Set_errno_for_invalid_flag_arguments_in_process_field.patch new file mode 100644 index 0000000..3827ef8 --- /dev/null +++ b/RHEL-132202-6-gfs2_edit_Set_errno_for_invalid_flag_arguments_in_process_field.patch @@ -0,0 +1,28 @@ +commit aa645d8035dcfbfb00d7ab5496019e8a04e56b61 +Author: Andrew Price +Date: Tue Dec 2 17:52:46 2025 +0000 + + gfs2_edit: Set errno for invalid flag arguments in process_field() + + sscanf() zeroes errno causing invalid flag arguments to be reported as + + Could not set 'di_flags' to '': Success + + Set errno to EINVAL to report validation failures in this section of + process_field() sensibly. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c +index 7e3a8a24..2dc7d0a7 100644 +--- a/gfs2/edit/hexedit.c ++++ b/gfs2/edit/hexedit.c +@@ -1763,6 +1763,7 @@ static void process_field(const char *field, const char *nstr) + } + if (val == 0) + err = sscanf(nstr, "%"SCNi64, &val); ++ errno = EINVAL; + if (err == 1) + /* coverity[overrun-buffer-val:SUPPRESS] False positive */ + err = lgfs2_field_assign(rbh->b_data, mfield, &val); diff --git a/RHEL-132202-7-libgfs2_Use_as_the_flag_separator_in_lgfs2_field_str.patch b/RHEL-132202-7-libgfs2_Use_as_the_flag_separator_in_lgfs2_field_str.patch new file mode 100644 index 0000000..a1ccae0 --- /dev/null +++ b/RHEL-132202-7-libgfs2_Use_as_the_flag_separator_in_lgfs2_field_str.patch @@ -0,0 +1,40 @@ +commit a83d4311da206711c3368c6be555c6ac16cb64e5 +Author: Andrew Price +Date: Wed Dec 3 15:44:56 2025 +0000 + + libgfs2: Use '|' as the flag separator in lgfs2_field_str() + + To make gfs2_edit's output consistent with its expected input. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/libgfs2/meta.c b/gfs2/libgfs2/meta.c +index 8b93c0a0..9fb43e05 100644 +--- a/gfs2/libgfs2/meta.c ++++ b/gfs2/libgfs2/meta.c +@@ -903,7 +903,7 @@ int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct + continue; + found = true; + if (s != str && s < end) +- *s++ = '/'; ++ *s++ = '|'; + if (s < end) { + const char *v = sym->value + sym->prefix; + size_t len = strlen(v); +diff --git a/tests/edit.at b/tests/edit.at +index 22a60f04..7aeaf70a 100644 +--- a/tests/edit.at ++++ b/tests/edit.at +@@ -78,9 +78,9 @@ GFS_TGT_REGEN + AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) + AT_CHECK([gfs2_edit -p journal0 field di_flags invalid_flag $GFS_TGT], 1, [ignore], [ignore]) + AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_SYSTEM], [ignore]) +-AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore]) ++AT_CHECK([gfs2_edit -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA|GFS2_DIF_SYSTEM], [ignore]) + AT_CHECK([gfs2_edit -x -p journal0 field di_flags 'GFS2_DIF_SYSTEM|GFS2_DIF_JDATA' $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore]) +-AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA/GFS2_DIF_SYSTEM], [ignore]) ++AT_CHECK([gfs2_edit -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [GFS2_DIF_JDATA|GFS2_DIF_SYSTEM], [ignore]) + AT_CHECK([gfs2_edit -x -p journal0 field di_flags $GFS_TGT | tr -d '\n'], 0, [0x201], [ignore]) + AT_CHECK([gfs2_edit -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0], [ignore]) + AT_CHECK([gfs2_edit -x -p journal0 field di_flags 0 $GFS_TGT | tr -d '\n'], 0, [0x0], [ignore]) diff --git a/RHEL-132202-8-gfs2_edit_Print_a_better_error_message_for_missing_path.patch b/RHEL-132202-8-gfs2_edit_Print_a_better_error_message_for_missing_path.patch new file mode 100644 index 0000000..f6e0ad0 --- /dev/null +++ b/RHEL-132202-8-gfs2_edit_Print_a_better_error_message_for_missing_path.patch @@ -0,0 +1,28 @@ +commit 3defe7201255961dc82720069a2b901ba3c6498a +Author: Andrew Price +Date: Wed Dec 3 16:02:22 2025 +0000 + + gfs2_edit: Print a better error message for missing path + + If gfs2_edit fails to parse the device path from argv it still passes + the device variable to open(2) which results in a "Bad address" error + message. Catch a NULL or empty path and report it as a missing path. + + Resolves: RHEL-132202 + Signed-off-by: Andrew Price + +diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c +index 2dc7d0a7..19b58ff9 100644 +--- a/gfs2/edit/hexedit.c ++++ b/gfs2/edit/hexedit.c +@@ -2575,6 +2575,10 @@ int main(int argc, char *argv[]) + if (dmode == INIT_MODE) + dmode = HEX_MODE; + ++ if (device == NULL || *device == '\0') { ++ fprintf(stderr, "No device path specified\n"); ++ exit(1); ++ } + fd = open(device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Failed to open '%s': %s\n", device, strerror(errno)); diff --git a/RHEL-143418-fsck_gfs2_Fix_rebuilding_bad_system_inodes.patch b/RHEL-143418-fsck_gfs2_Fix_rebuilding_bad_system_inodes.patch new file mode 100644 index 0000000..0fb4106 --- /dev/null +++ b/RHEL-143418-fsck_gfs2_Fix_rebuilding_bad_system_inodes.patch @@ -0,0 +1,137 @@ +commit d1392bb22bae2d82b589aefb267be93c22576bff +Author: Andrew Price +Date: Thu Jan 15 17:30:12 2026 +0000 + + fsck.gfs2: Fix rebuilding bad 'system' inodes + + When these inodes are scribbled over, the fsck.gfs2 builder functions + called by check_system_inode() don't rebuild them properly. Firstly, + they free the rebuilt inode causing a subsequent segfault; and secondly + they don't remove the directory entry before rebuilding, causing the + lgfs2_createi() call used by libgfs2 builder functions to just return + the existing broken inode. Fix these two issues in each of the system + inode builder functions. + + Resolves: RHEL-143418 + Signed-off-by: Andrew Price + +diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c +index 206929fc..49f51f53 100644 +--- a/gfs2/fsck/pass1.c ++++ b/gfs2/fsck/pass1.c +@@ -1465,6 +1465,8 @@ static int check_system_inode(struct fsck_cx *cx, + if (query(cx, _("Create new %s system inode? (y/n) "), filename)) { + log_err( _("Rebuilding system file \"%s\"\n"), + filename); ++ lgfs2_inode_free(sysinode); ++ lgfs2_dirent_del(sysdir, filename, strlen(filename)); + error = builder(cx->sdp); + if (error || *sysinode == NULL) { + log_err( _("Error rebuilding system " +@@ -1581,8 +1583,8 @@ static int build_inum(struct lgfs2_sbd *sdp) + struct lgfs2_inode *ip = lgfs2_build_inum(sdp); + if (ip == NULL) + return -1; +- lgfs2_inode_put(&ip); +- return 0; ++ sdp->md.inum = ip; ++ return lgfs2_init_inum(sdp); + } + + static int build_statfs(struct lgfs2_sbd *sdp) +@@ -1590,8 +1592,8 @@ static int build_statfs(struct lgfs2_sbd *sdp) + struct lgfs2_inode *ip = lgfs2_build_statfs(sdp); + if (ip == NULL) + return -1; +- lgfs2_inode_put(&ip); +- return 0; ++ sdp->md.statfs = ip; ++ return lgfs2_init_statfs(sdp, NULL); + } + + static int build_rindex(struct lgfs2_sbd *sdp) +@@ -1599,8 +1601,9 @@ static int build_rindex(struct lgfs2_sbd *sdp) + struct lgfs2_inode *ip = lgfs2_build_rindex(sdp); + if (ip == NULL) + return -1; +- lgfs2_inode_put(&ip); +- return 0; ++ sdp->md.riinode = ip; ++ lgfs2_dinode_out(ip, ip->i_bh->b_data); ++ return lgfs2_bwrite(ip->i_bh); + } + + static int build_quota(struct lgfs2_sbd *sdp) +@@ -1608,8 +1611,9 @@ static int build_quota(struct lgfs2_sbd *sdp) + struct lgfs2_inode *ip = lgfs2_build_quota(sdp); + if (ip == NULL) + return -1; +- lgfs2_inode_put(&ip); +- return 0; ++ sdp->md.qinode = ip; ++ lgfs2_dinode_out(ip, ip->i_bh->b_data); ++ return lgfs2_bwrite(ip->i_bh); + } + + static int check_system_inodes(struct fsck_cx *cx) +diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c +index ba9434af..2f6b2828 100644 +--- a/gfs2/libgfs2/fs_ops.c ++++ b/gfs2/libgfs2/fs_ops.c +@@ -115,7 +115,8 @@ void lgfs2_inode_free(struct lgfs2_inode **ipp) + { + struct lgfs2_inode *ip = *ipp; + +- free(ip->i_bh); ++ if (ip) ++ free(ip->i_bh); + free(ip); + *ipp = NULL; + } +diff --git a/tests/fsck.at b/tests/fsck.at +index 538d41ad..c860d432 100644 +--- a/tests/fsck.at ++++ b/tests/fsck.at +@@ -75,6 +75,42 @@ AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore]) + AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore]) + AT_CLEANUP + ++AT_SETUP([Rebuild bad statfs]) ++AT_KEYWORDS(fsck.gfs2 fsck) ++GFS_TGT_REGEN ++AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([gfs2_edit -p statfs field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore]) ++AT_CLEANUP ++ ++AT_SETUP([Rebuild bad inum]) ++AT_KEYWORDS(fsck.gfs2 fsck) ++GFS_TGT_REGEN ++AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([gfs2_edit -p inum field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore]) ++AT_CLEANUP ++ ++AT_SETUP([Rebuild bad rindex]) ++AT_KEYWORDS(fsck.gfs2 fsck) ++GFS_TGT_REGEN ++AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([gfs2_edit -p rindex field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore]) ++AT_CLEANUP ++ ++AT_SETUP([Rebuild bad quota]) ++AT_KEYWORDS(fsck.gfs2 fsck) ++GFS_TGT_REGEN ++AT_CHECK([mkfs.gfs2 -O -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([gfs2_edit -p quota field di_header.mh_magic 0 $GFS_TGT], 0, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -y $GFS_TGT], 1, [ignore], [ignore]) ++AT_CHECK([fsck.gfs2 -n $GFS_TGT], 0, [ignore], [ignore]) ++AT_CLEANUP ++ + AT_SETUP([gfs2 format versions]) + AT_KEYWORDS(fsck.gfs2 fsck) + GFS_TGT_REGEN diff --git a/gfs2-utils.spec b/gfs2-utils.spec index 12d79f0..00b5e40 100644 --- a/gfs2-utils.spec +++ b/gfs2-utils.spec @@ -1,6 +1,6 @@ Name: gfs2-utils Version: 3.5.1 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv2+ and LGPLv2+ Summary: Utilities for managing the global file system (GFS2) %ifnarch %{arm} @@ -22,6 +22,15 @@ BuildRequires: make Source: https://releases.pagure.org/gfs2-utils/gfs2-utils-%{version}.tar.gz URL: https://pagure.io/gfs2-utils Patch0: RHEL-26661-gfs2_edit_truncate_to_filesystem_size_at_end_of_restoremeta.patch +Patch1: RHEL-132202-1-gfs2_edit_Use_0x_notation_when_printing_hexadecimal_values.patch +Patch2: RHEL-132202-2-libgfs2_Add_a_function_to_look_up_flags_by_symbol.patch +Patch3: RHEL-132202-3-gfs2_edit_Allow_setting_flags_fields_using_symbols.patch +Patch4: RHEL-132202-4-gfs2_edit_Only_call_ioctl_BLKFLSBUF_on_block_devices.patch +Patch5: RHEL-132202-5-libgfs2_Fall_back_to_printing_a_numerical_value_in_lgfs2_field_str.patch +Patch6: RHEL-132202-6-gfs2_edit_Set_errno_for_invalid_flag_arguments_in_process_field.patch +Patch7: RHEL-132202-7-libgfs2_Use_as_the_flag_separator_in_lgfs2_field_str.patch +Patch8: RHEL-132202-8-gfs2_edit_Print_a_better_error_message_for_missing_path.patch +Patch9: RHEL-143418-fsck_gfs2_Fix_rebuilding_bad_system_inodes.patch %prep %autosetup -p1 @@ -64,6 +73,19 @@ modifying, and correcting inconsistencies in GFS2 file systems. %{_prefix}/lib/udev/rules.d/82-gfs2-withdraw.rules %changelog +* Tue Feb 03 2026 Andrew Price - 3.5.1-3 +- gfs2_edit: Use 0x notation when printing hexadecimal values +- libgfs2: Add a function to look up flags by symbol +- gfs2_edit: Allow setting flags fields using symbols +- gfs2_edit: Only call ioctl(BLKFLSBUF) on block devices +- libgfs2: Fall back to printing a numerical value in lgfs2_field_str() +- gfs2_edit: Set errno for invalid flag arguments in process_field() +- libgfs2: Use '|' as the flag separator in lgfs2_field_str() +- gfs2_edit: Print a better error message for missing path + Resolves: RHEL-132202 +- fsck.gfs2: Fix rebuilding bad 'system' inodes + Resolves: RHEL-143418 + * Fri Jun 21 2024 Andrew Price - 3.5.1-2 - gfs2_edit: truncate to filesystem size at end of restoremeta() Resolves: RHEL-26661