Should /usr/include/fts.h adding fts_dirfd and __fts_reserved[3] to FTSENT (a.k.a. struct _ftsent) require a change from libc.so.7 to .8 because of some resulting binary incompatibilities?
Date: Thu, 24 Sep 2026 23:37:09 UTC
The SHLIB_MAJOR last changed on 2006-05-21 and is:
LIB=c
SHLIB_MAJOR= 7
Changes to the binary interface for function (pointers) passed into any
FreeBSD libc inteferface functions lead to incompatibilities. In this
case FTSENT (a.k.a. struct _ftsent) is used via function arguments in:
FTS *fts_open(char * const *, int,
int (*)(const FTSENT * const *, const FTSENT * const *));
FTS *fts_openat(int, char * const *, int,
int (*)(const FTSENT * const *, const FTSENT * const *));
#ifdef __BLOCKS__
FTS *fts_open_b(char * const *, int,
int (^)(const FTSENT * const *, const FTSENT * const *));
but, as of 2026-08-03, the content of the *FTSENT (i.e.,
struct _ftsent) was updated in a non-binary compatible way:
author Jitendra Bhati <bhatijitendra2022@gmail.com> 2026-06-12 17:07:55
+0000
committer Alan Somers <asomers@FreeBSD.org> 2026-08-03 19:12:28 +0000
commit 4bd01d6ae01632501b63438b8d9a401db9744a78 (patch)
tree e896c1844fa0fa5897efc4e591ebe02f59a64e61 /include/fts.h
parent 9590878fca68e62c63d607da73139698e204d0f0 (diff)
. . .
Sponsored by: Google LLC (GSoC 2026)
Reviewed by: asomers
Pull Request: https://github.com/freebsd/freebsd-src/pull/2303
Diffstat (limited to 'include/fts.h')
-rw-r--r-- include/fts.h 2
1 files changed, 2 insertions, 0 deletions
diff --git a/include/fts.h b/include/fts.h
index 479905bda463..0308b8ff880b 100644
--- a/include/fts.h
+++ b/include/fts.h
@@ -92,6 +92,8 @@ struct _ftsent {
char *fts_path; /* root path */
int fts_errno; /* errno for this node */
int fts_symfd; /* fd for symlink */
+ int fts_dirfd; /* fd for parent directory */
+ int __fts_reserved[3]; /* reserved for future use */
__size_t fts_pathlen; /* strlen(fts_path) */
__size_t fts_namelen; /* strlen(fts_name) */
There is a lot more after what is visible in the diff (starting with the
inserted fields to have it all together):
int fts_dirfd; /* fd for this directory, if a directory */
int __fts_reserved[3]; /* reserved for future use */
__size_t fts_pathlen; /* strlen(fts_path) */
__size_t fts_namelen; /* strlen(fts_name) */
__ino_t fts_ino; /* inode */
__dev_t fts_dev; /* device */
__nlink_t fts_nlink; /* link count */
#define FTS_ROOTPARENTLEVEL -1
#define FTS_ROOTLEVEL 0
long fts_level; /* depth (-1 to N) */
#define FTS_D 1 /* preorder directory */
. . .
#define FTS_W 14 /* whiteout object */
int fts_info; /* user status for FTSENT structure */
#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */
#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */
#define FTS_ISW 0x04 /* this is a whiteout object */
unsigned fts_flags; /* private flags for FTSENT structure */
#define FTS_AGAIN 1 /* read node again */
...
#define FTS_SKIP 4 /* discard node */
int fts_instr; /* fts_set() instructions */
struct stat *fts_statp; /* stat(2) information */
char *fts_name; /* file name */
FTS *fts_fts; /* back pointer to main FTS */
};
An example is in src/tree/lib/libpmc/pmu-events/jevents.c that has:
#include <fts.h>
static int
#if defined(__linux__) || defined(__APPLE__)
fts_compare(const FTSENT **a, const FTSENT **b)
#else
fts_compare(const FTSENT * const *a, const FTSENT * const *b)
#endif
{
return (strcmp((*a)->fts_name, (*b)->fts_name));
}
Note that the compile time offset for ->fts_name change changes
depending on which header version was used and that it will not track
the environment that jevents is run in.
The same jevent executable file's fts_compare code (non-linux/non-apple)
is compatible with only one of:
) a libc.so.7 *FTSENT from before the 2026-08-03 change
vs.
) a libc.so.7 *FTSENT from after the 2026-08-03 change
I have observed SIGSEGV with backtraces that show the failure at such a
fts_compare (*?)->fts_name based deference. That is what eventually
resulted in my noticing the above in this unfamiliar code.
--
===
Mark Millard
marklmi at yahoo.com