F45 Change Proposal: ODBC Stack Modernization (self-contained)

ODBC Stack Modernization

This is a proposed Change for Fedora Linux.
This document represents a proposed Change. As part of the Changes process, proposals are publicly announced in order to receive community feedback. This proposal will only be implemented if approved by the Fedora Engineering Steering Committee.

Wiki
Announced

:link: Summary

Modernize the Fedora ODBC stack across 7 packages (unixODBC and 6 driver packages: mariadb-connector-odbc, mysql-connector-odbc, postgresql-odbc, freetds, sqliteodbc, mdbtools). The central change is replacing the static, centrally-maintained /etc/odbcinst.ini driver registration file with an auto-generated configuration assembled from per-driver drop-in snippets, using RPM file triggers — the same pattern used by ldconfig, ca-certificates, and crypto-policies. Supporting changes include switching to bare library names resolved via a compiled-in search path, moving driver plugins to a dedicated directory, and general spec cleanups.

:link: Owner

:link: Proposed code changes

All changes are in the dropin-registration topic branches in the Chnage owner’s forks:

:link: Detailed Description

:link: Background

The ODBC driver manager (unixODBC) uses /etc/odbcinst.ini to map driver names to shared libraries. In Fedora, this file has historically been shipped as %config(noreplace) inside the unixODBC package, pre-populated with entries for all known Fedora ODBC drivers.

The driver entries in Fedora were in poor shape. FileUsage values were wrong for multiple drivers, library paths were hardcoded and multilib-unfriendly, and the FreeTDS entry contained a dead Port key that the driver never reads from odbcinst.ini. These problems persisted because driver entries lived in the wrong package — fixing a driver’s registration required a change to unixODBC, not to the driver package itself.

This coupling created several structural problems:

  • Wrong ownership: Driver packages had no control over their own registration. A driver maintainer who wanted to fix or update their entry had to coordinate a change in unixODBC.
  • Stale entries: All known drivers were pre-populated in the config regardless of whether they were installed, leading to broken references.
  • Invisible drivers: New driver packages (e.g. mdbtools-odbc) were not registered at all until someone manually added them to the unixODBC spec. mdbtools-odbc was invisible to ODBC applications after install.
  • Fragile upgrades: The %config(noreplace) semantics mean RPM silently keeps the old file on upgrade, so corrections (like fixed FileUsage values) never reach existing installations.

Of all 6 driver packages in Fedora, only sqliteodbc attempted self-registration via %post/%preun scriptlets calling odbcinst -i/odbcinst -u. The other 5 relied entirely on unixODBC pre-populating their entries.

:link: What is changing

The modernization consists of two groups of changes:

Already in Fedora Rawhide (foundation work):

  • ODBC driver plugins moved from %{_libdir} to a dedicated %{_libdir}/odbc/ directory across all driver packages.
  • unixODBC compiled with --with-odbc-driver-path=%{_libdir}/odbc, enabling bare library names (e.g. Driver = libmaodbc.so instead of full paths).
  • FileUsage values corrected across all drivers (BZ#2453060).
  • Suggests: added for all 6 ODBC driver packages.
  • Removal of a 17-year-old dead patch (keep-typedefs.patch).

Proposed in this change (driver registration):

  • Each driver package ships a static .ini snippet file to /usr/lib/odbc/odbcinst.d/ (vendor defaults).
  • unixODBC owns %transfiletriggerin and %transfiletriggerpostun scriptlets that run a regeneration script (odbcinst-generate) whenever snippets are installed or removed.
  • The regeneration script merges all snippets (vendor defaults overlaid by admin overrides) and atomically replaces /etc/odbcinst.ini.
  • /etc/odbcinst.ini changes from %config(noreplace) to %ghost — RPM tracks ownership but the file is never shipped; it is always generated.
  • Administrators can override or disable vendor drivers via /etc/odbc/odbcinst.d/ (see below).

:link: Drop-in directory layout

/usr/lib/odbc/odbcinst.d/ ← vendor snippets (shipped by driver RPMs) 10-mariadb.ini 10-mysql.ini 10-postgresql.ini 10-freetds.ini 10-sqlite.ini 10-mdbtools.ini /etc/odbc/odbcinst.d/ ← admin overrides and additions /etc/odbcinst.ini ← generated output (%ghost)

Override semantics:

  • Files are named NN-name.ini. The numeric prefix controls merge order.
  • Vendor range: 10–49. Admin range: 50–99.
  • When two files share the same name after stripping the prefix (e.g. 10-mariadb.ini and 60-mariadb.ini), the higher-numbered one wins.
  • To disable a vendor driver, symlink its snippet to /dev/null:

ln -sf /dev/null /etc/odbc/odbcinst.d/10-freetds.ini

  • To apply changes after editing drop-in files manually, run: odbcinst-generate

These semantics follow the established systemd convention used throughout Fedora.

:link: Precedent

This is the standard Fedora pattern for generated configuration. At least 22 packages use the same %transfiletriggerin + regeneration model, including:

  • glibc-common/etc/ld.so.conf.d/ldconfig/etc/ld.so.cache
  • ca-certificates/etc/pki/ca-trust/source/update-ca-trustca-bundle.crt
  • crypto-policies/usr/share/crypto-policies/update-crypto-policies
  • fontconfig/usr/share/fonts/fc-cache
  • shared-mime-info/usr/share/mime/update-mime-database
  • glib2/usr/share/glib-2.0/schemas/glib-compile-schemas

:link: Migration strategy (for FESCo consideration)

This is the area where community input is most welcome.

When upgrading from a system where /etc/odbcinst.ini was %config(noreplace) to the new %ghost model, RPM does not automatically create an .rpmsave backup. Without intervention, any user modifications to odbcinst.ini would be silently lost.

The proposed migration strategy:

  1. A %pretrans Lua scriptlet in unixODBC detects first-time upgrades (the drop-in directory does not yet exist) and renames /etc/odbcinst.ini to /etc/odbcinst.ini.rpmsave. On subsequent upgrades (drop-in directory already exists), the %pretrans is a no-op.
  2. %post checks whether /etc/odbcinst.ini.rpmsave exists. If so, it prints a notice to stderr explaining that driver registration has moved to drop-in snippets, pointing users to the .rpmsave file and explaining how to migrate custom entries. This notice is repeated on every upgrade as long as the .rpmsave file remains, serving as a persistent reminder until the user completes the migration and removes it.

What users need to do:

  • Users who never modified odbcinst.ini: nothing. All standard drivers are registered automatically via snippets.
  • Users who added custom driver entries: copy their custom [sections] from odbcinst.ini.rpmsave into a new file under /etc/odbc/odbcinst.d/ and run odbcinst-generate.

Alternatives considered:

  • Content-based detection (parse the file to detect user modifications): rejected as unreliable in RPM’s limited Lua environment.
  • Always preserve (never create .rpmsave): rejected because it leaves the old static file alongside the new generated one, causing confusion.
  • In-place migration (automatically convert user entries to drop-in files): rejected as too complex and opaque. Users should be aware of the new mechanism.

:link: Rejected ideas: scriptlet-based registration (Debian/Ubuntu, openSUSE)

Other distributions use odbcinst -i/odbcinst -u commands in driver package scriptlets (postinst/postrm on Debian, %post/%preun on openSUSE). I considered and rejected this for Fedora due to various bugs present in this approach.

How it works in Debian/Ubuntu: Each driver package calls odbcinst -i -d -f /usr/share/<driver>/odbcinst.ini.template in its postinst and odbcinst -u -d in its postrm. This approach has generated real bugs over more than a decade:

  • Ubuntu Bug #1173083: tdsodbc used a debconf prompt to ask whether to register the driver. In automated installs (containers, CI, preseed), the question was never answered, leaving FreeTDS silently unregistered. Open for 12 years before being fixed.
  • Debian Bug #1001141: odbc-mariadb called odbcinst in its maintainer scripts but did not declare a dependency on the odbcinst binary, causing silent registration failures.

How it works in openSUSE: Similar, using RPM %post/%preun scriptlets. All errors are suppressed with > /dev/null 2>&1 || true, so failures are completely silent. Coverage is inconsistent: only 3 of 5 driver packages self-register; mariadb-connector-odbc ships a sample .ini but no scriptlets; mdbtools has its ODBC driver incorrectly placed in the -devel subpackage.

Why the scriptlet approach is fundamentally fragile:

  • Race conditions: odbcinst performs a read-modify-write cycle on /etc/odbcinst.ini without file locking. If two driver packages run scriptlets concurrently, the file can be corrupted or one registration silently lost.
  • Reference counting: odbcinst maintains a reference count per driver entry. A failed or interrupted scriptlet can leave the count out of sync, resulting in stale entries that never get removed or premature removal of valid entries.
  • Cross-package file modification: Multiple independent packages all modify a file owned by unixODBC, violating single file ownership.
  • Per-driver boilerplate: Every driver package must independently implement registration logic, template files, and correct dependency declarations. Each one is a potential source of bugs.

Why the drop-in approach is better: RPM file triggers (%transfiletriggerin) are transactional — they fire once after the entire transaction completes, not once per package. The regeneration script rebuilds /etc/odbcinst.ini from scratch using only the snippet files currently on disk. There is no read-modify-write race, no reference counting, no possibility of stale entries, and driver packages need zero scriptlet logic — they ship a static file and nothing else.

With this change, Fedora would be the first distribution with a systemic, race-free, declarative ODBC driver registration mechanism with first-class admin override semantics.

:link: Feedback

:link: Benefit to Fedora

  • Decoupled driver registration: Each driver package owns its own registration. Adding a new ODBC driver to Fedora no longer requires changes to unixODBC.
  • Correct out-of-the-box experience: Only installed drivers appear in the config. Installing a driver automatically makes it visible to applications; removing it automatically cleans up. This fixes the long-standing problem where mdbtools-odbc was installable but invisible to ODBC applications.
  • Admin override mechanism: System administrators can override vendor defaults or disable drivers without editing generated files, using the same drop-in pattern familiar from systemd, ldconfig, and crypto-policies.
  • Bare library names: Driver entries use plain library names (e.g. Driver = libmaodbc.so) resolved via a compiled-in search path, eliminating hardcoded %{_libdir} paths and multilib ambiguity.
  • Correct metadata: FileUsage values are fixed across all drivers. Fedora becomes the first distribution to ship correct values for all its ODBC drivers.
  • Reduced spec complexity: Driver packages no longer need %post/%preun scriptlets for registration. A single static .ini file per driver replaces all of it.

:link: Scope

  • Proposal owners:

    • Implement drop-in infrastructure in unixODBC (directories, regeneration script, file triggers, %ghost config, migration scriptlets)
    • Add drop-in snippet files to all 6 driver packages: mariadb-connector-odbc, mysql-connector-odbc, postgresql-odbc, freetds, sqliteodbc, mdbtools
    • Remove legacy %post/%preun odbcinst scriptlets from sqliteodbc
    • Test upgrade scenarios in containers via COPR
  • Other developers:

    • No action required from other package maintainers. The change is self-contained within the 7 packages listed above.
  • Release engineering: N/A (not a System Wide Change)

  • Policies and guidelines: N/A

  • Trademark approval: N/A

  • Alignment with the Fedora Strategy: Fedora leads in the Linux distribution development. This change adopts a modern, well-established Fedora pattern for an area of the stack that has lagged behind.

:link: Upgrade/compatibility impact

On upgrade from a previous Fedora release:

  • /etc/odbcinst.ini is saved as /etc/odbcinst.ini.rpmsave.
  • A new /etc/odbcinst.ini is generated from drop-in snippets.
  • All standard drivers (MariaDB, MySQL, PostgreSQL, FreeTDS, SQLite, MDBTools) are registered automatically if their packages are installed.
  • Users with custom driver entries in the old odbcinst.ini need to migrate them to drop-in snippet files under /etc/odbc/odbcinst.d/. A notice is printed during upgrade with instructions.

Applications using ODBC continue to work without changes. The generated odbcinst.ini uses the same INI format as before; only the mechanism that produces it has changed.

:link: How To Test

Test builds are available in COPR: mschorm/ODBC

Fresh install (no previous ODBC config):

  1. Install unixODBC and one or more driver packages
  2. Verify /etc/odbcinst.ini is generated and contains entries for the installed drivers
  3. Verify that uninstalling a driver package removes its entry from odbcinst.ini

Upgrade from current Rawhide (unmodified config):

  1. Start with a system running the current unixODBC (pre-drop-in)
  2. Upgrade to the new version
  3. Verify /etc/odbcinst.ini.rpmsave is created
  4. Verify the new /etc/odbcinst.ini contains correct entries for installed drivers

Upgrade with custom driver entries:

  1. Start with a system where /etc/odbcinst.ini has been manually edited (e.g. a custom [MyDriver] section added)
  2. Upgrade to the new version
  3. Verify /etc/odbcinst.ini.rpmsave preserves the custom entries
  4. Copy the custom section into /etc/odbc/odbcinst.d/60-mydriver.ini
  5. Run odbcinst-generate
  6. Verify the custom driver appears in the regenerated /etc/odbcinst.ini

Admin override:

  1. Install mariadb-connector-odbc (ships 10-mariadb.ini)
  2. Create /etc/odbc/odbcinst.d/60-mariadb.ini with modified settings
  3. Run odbcinst-generate
  4. Verify the admin override takes precedence

Driver disable:

  1. ln -sf /dev/null /etc/odbc/odbcinst.d/10-freetds.ini
  2. Run odbcinst-generate
  3. Verify FreeTDS no longer appears in /etc/odbcinst.ini

:link: User Experience

For most users, the change is invisible. Installing an ODBC driver package automatically registers it; removing it automatically unregisters it. No manual odbcinst commands are needed.

Power users and administrators gain a familiar drop-in override mechanism. Customizing ODBC driver registration now works the same way as customizing library paths (ld.so.conf.d) or CA certificates (ca-trust).

Users upgrading from a previous Fedora release who had custom entries in odbcinst.ini will see a migration notice on each upgrade until they complete the migration and remove the .rpmsave file.

:link: Dependencies

All 7 affected packages are maintained by the change owner:

  • unixODBC
  • mariadb-connector-odbc
  • mysql-connector-odbc
  • postgresql-odbc
  • freetds
  • sqliteodbc
  • mdbtools

No other packages are affected. The generated /etc/odbcinst.ini is format-compatible with the previous static file.

:link: Contingency Plan

  • Contingency mechanism: Revert the unixODBC spec to ship a static %config(noreplace) odbcinst.ini and remove drop-in snippet files from driver packages. This is a straightforward revert of the topic branch in each package.
  • Contingency deadline: N/A (not a System Wide Change)
  • Blocks release? No

:link: Documentation

  • BZ#2453060 — Standardize unixODBC connector installation directory
  • COPR test repository: mschorm/ODBC
  • A new odbcinst-generate(1) man page will be shipped with the unixODBC package, documenting the regeneration tool, drop-in directory layout, and override semantics
  • The existing upstream odbcinst.ini(5) man page will be updated or supplemented with a note about the drop-in mechanism

:link: Release Notes

The ODBC driver stack has been modernized. ODBC driver registration now uses a drop-in snippet mechanism: each driver package ships a small .ini file that is automatically merged into /etc/odbcinst.ini when the package is installed or removed. Administrators can override vendor defaults or add custom drivers by placing files in /etc/odbc/odbcinst.d/.

Users who had custom entries in /etc/odbcinst.ini will find their previous configuration saved as /etc/odbcinst.ini.rpmsave after upgrading. Custom driver sections should be migrated to individual files under /etc/odbc/odbcinst.d/.

Last edited by @amoloney 2026-07-13T17:10:02Z

Last edited by @amoloney 2026-07-13T17:10:02Z

How do you feel about the proposal as written?

  • Strongly in favor
  • In favor, with reservations
  • Neutral
  • Opposed, but could be convinced
  • Strongly opposed
0 voters

If you are in favor but have reservations, or are opposed but something could change your mind, please explain in a reply.

We want everyone to be heard, but many posts repeating the same thing actually makes that harder. If you have something new to say, please say it. If, instead, you find someone has already covered what you’d like to express, please simply give that post a :heart: instead of reiterating. You can even do this by email, by replying with the heart emoji or just “+1”. This will make long topics easier to follow.

Please note that this is an advisory “straw poll” meant to gauge sentiment. It isn’t a vote or a scientific survey. See About the Change Proposals category for more about the Change Process and moderation policy.

Hello Michal, all,

First: +1 on the direction. Moving driver registration to a drop-in
directory regenerated by an RPM file trigger is the right model - it is the
same proven pattern as ldconfig / ca-certificates / crypto-policies, and
decoupling driver packages from a centrally-owned /etc/odbcinst.ini is
overdue.

Disclosure of interest, so this doesn’t read as a drive-by: I’m working on
SeerODBC, a clean-room ODBC driver for Oracle (native TNS/TTC wire protocol,
no Instant Client) that is explicitly built to load under both unixODBC
and iODBC. That dual-driver-manager goal is exactly why the details below
matter to me, and why I’d like to help get them right while the Change is
still WIP rather than after F45 ships.

Two concerns and a couple of smaller asks.

  1. iODBC is unaddressed, and I believe it’s a real gap, not a nitpick.

Fedora ships libiodbc (currently libiodbc-3.52.16, multilib), and both
driver managers read the same /etc/odbcinst.ini by default. So the file
this Change regenerates is a shared interface with two consumers, but only
unixODBC is in scope. Two failure modes follow:

(a) The regeneration %transfiletriggerin lives in the unixODBC package.
iODBC does not depend on unixODBC, so a libiodbc-only host never
regenerates the file - the drivers go invisible, which is the exact
problem the Change sets out to solve, merely relocated.

(b) More fundamentally, “bare library names” plus the move of plugins to
%{_libdir}/odbc/ are unixODBC-private resolution semantics. iODBC has
no equivalent driver-path search; it accepts a section name or an
absolute path in Driver=, not a bare soname resolved against a private
directory. Once the plugin lives outside the loader path, a generated
Driver = libfoo.so will dlopen-fail under iODBC even when the file
is present.

Worth noting the ABI itself is not the problem: both managers dlopen the
same SQL* entry points, and on x86_64 both now agree on SQLLEN width
(unixODBC reports SQLLEN Size 8, iODBC 3.52 uses long on LP64), so a single
driver binary is loadable by both. It is specifically the bare name in the
shared config file
that breaks the second consumer.

  1. The fix is small and keeps the whole architecture: have
    odbcinst-generate resolve bare names to absolute, arch-correct paths at
    generation time.

The generator already exists, already runs locally per-transaction, and
already knows the machine’s architecture. Let the vendor snippets stay
noarch and bare (Driver = libfoo.so), but have the generated
/etc/odbcinst.ini carry “/usr/lib64/odbc/libfoo.so”. Then:

  • both driver managers get a path they can actually dlopen;
  • multilib is resolved exactly once, in the one arch-aware place, instead
    of being pushed onto every consumer of the file;
  • iODBC works without needing a second trigger or a unixODBC dependency.

This reframes the current bare-name decision as “right idea, wrong layer”:
the ambiguity belongs in the local, arch-aware generator, not in a shared
config file read by a manager that cannot interpret it.

  1. Smaller: the first-upgrade migration notice looks heavier than it needs
    to be.

The %pretrans Lua rename to .rpmsave is defensible - a
%config(noreplace) → %ghost transition genuinely needs hand-holding. But a
%post notice that persists until .rpmsave is manually removed will nag the
large majority who never edited /etc/odbcinst.ini. Consider gating the
rename+notice on a checksum comparison against the last-shipped default:
if the file is unmodified, drop it silently with no message. Scope the
disruption to files that were actually customized.

  1. Smaller: please document a reserved numeric range and tie-break rule.

10-49 vendor / 50-99 admin is good, but out-of-distro drivers - COPR
packages, third-party connectors, and yes, SeerODBC before it lands in
Fedora proper - need a reserved band and a defined collision behavior
(filename-sort, last-wins?) in the odbcinst-generate(1) man page, so two
out-of-tree drivers don’t both grab, say, [Oracle].

If the generator-resolves-absolute-paths approach in (2) is acceptable, I’m
happy to help with a patch and to test the result against both unixODBC and
iODBC. Either way, one explicit sentence in the Change on whether iODBC is
in scope would help packagers a lot.

Thanks for driving this - it’s a good cleanup.

2 Likes

Hi Peter,

This is fantastic feedback — thanks for taking the time!
I’ve implemented changes addressing 3/4 of the points.

Bare names → absolute paths in generated output

Agreed, and implemented. odbcinst-generate now resolves bare Driver and Setup values to absolute, architecture-correct paths at generation time. The snippets stay noarch-portable with bare names (Driver = libmaodbc.so), but the
generated /etc/odbcinst.ini carries absolute paths (Driver = /usr/lib64/odbc/libmaodbc.so). The generator detects the native ODBC library directory (/usr/lib64/odbc on 64-bit, /usr/lib/odbc on 32-bit) and applies a single sed pass
before the atomic replace.

Migration notice scoped to actual modifications

That unconditional nag was unintended — I definitely don’t want to alarm users who never touched their config.

I investigated the checksum approach you suggested, but it turns out to be impractical for this specific file: there are 22 distinct stock file variants across Fedora versions (library paths changed multiple times, sections were
added/removed, FileUsage values corrected), and on top of that, sqliteodbc’s %post historically injected architecture-specific [SQLITE]/[SQLITE3] sections via odbcinst -i, creating further permutations. RPM’s embedded Lua also has no
digest functions, so we’d need io.popen("sha256sum ..."), which violates packaging guidelines for %pretrans.

I went with content-based section matching instead: the %pretrans Lua scriptlet parses the file for INI [Section] headers and checks each against the set of drivers historically shipped by Fedora (PostgreSQL, MySQL, MySQL-5, FreeTDS,
MariaDB, MDBTools, SQLITE, SQLITE3). If every section is known, the file is stock and gets silently dropped — the snippets will regenerate equivalent entries. Only files with unknown sections (user-added custom drivers) are saved as
.rpmsave with a migration notice.

This may miss the case where a user edited a key within a known section (e.g. changed a Driver path), but those modifications would be superseded by the new snippets anyway — the whole point of this change is that the old values were
wrong. The only user work worth preserving is custom driver entries, which is exactly what the section check catches.

Numeric ranges and tie-break rules

Implemented. The numeric range is now split into three bands:

  • 10–29: Distro vendor (Fedora-shipped driver packages)
  • 30–49: Third-party / out-of-tree (COPR, vendor RPMs — SeerODBC would go here)
  • 50–99: Administrator overrides and additions

Tie-break rules are explicitly documented in the odbcinst-generate(1) man page: admin directory always wins over vendor directory for the same stripped name (regardless of prefix); within the same directory, higher prefix wins. For
collision avoidance, third-party packagers should use unique names (30-seerodbc.ini, 31-oracle-instantclient.ini); duplicate filenames within a directory are an RPM file conflict.

I tried to stick to precedents already in Fedora (sysctl.d, tmpfiles.d, modprobe.d). However, there’s one deliberate deviation: those systems use exact filename matching, where /etc/sysctl.d/60-foo.conf and /usr/lib/sysctl.d/10-foo.conf
coexist as separate files with per-key resolution. ODBC registration uses stripped-name matching instead, because each snippet declares a complete [DriverName] INI section — merging keys from two [MariaDB] sections across files would
be ambiguous. The entire section is the atomic unit, so the override must be a whole-section replacement. The man page includes a NOTES section explaining this rationale with cross-references to sysctl.d(5) and tmpfiles.d(5).

iODBC

iODBC remains unaddressed for now. unixODBC currently carries Conflicts: iodbc, so both cannot be installed simultaneously, and the absolute-path resolution means the generated file would work for iODBC if it could read it.

The open question is how to make the trigger fire on iODBC-only hosts. We could move odbcinst-generate and the file triggers into a small subpackage (e.g. unixODBC-common) or a separate package (e.g. odbcinst-generate) that both unixODBC and libiodbc could
depend on. This would also be a natural home for the drop-in directories and the %ghost config file. I’d welcome input on whether this layering makes sense before committing to it — it would affect the Conflicts: iodbc relationship as well.


I updated the unixODBC commit.
I updated the Fedora Change page
I submitted new build of the unixODBC to the test COPR.

Would you please re-review the Change?

Hi Michal,

This is great - thanks for the fast and thorough turnaround. Three of four fully addressed, and the responses on the ones I raised are well-reasoned. Quick re-review:

Bare → absolute paths. Exactly what was needed - the generated file is now portable to any driver manager, which is the whole ballgame. Two small, optional hardenings for later (non-blocking):

  • The sed rewrites unconditionally; consider only rewriting when the .so is actually found under the driver dir, so a driver that lives outside /usr/lib*/odbc (a third-party one using a bare name) doesn’t get rewritten to a non-existent path that then fails dlopen under both managers. Leaving an unresolved bare name in place preserves today’s behavior.
  • Related: you pick one libdir globally (/usr/lib64/odbc if that dir exists, else /usr/lib/odbc). A 32-bit-only driver on a multilib host would then be rewritten to a wrong lib64 path. Resolving per-driver (probe lib64 then lib for each name) handles that. Rare, but essentially free to make robust.

Migration notice. Your content-based section matching is a better fit than checksumming here - I hadn’t accounted for the 22 stock variants or the sqliteodbc %post injection, and the %pretrans Lua digest constraint is a real one. Matching [Section] headers against the known-shipped set, and only preserving files with unknown (= user-added) sections, captures exactly the work worth keeping. Agreed on the trade-off for edited-keys-in-known-sections; those were the wrong values this Change exists to fix.

Ranges + tie-break. The three-band split is clear, and thank you for carving out 30-49 for third-party. The sysctl.d/tmpfiles.d deviation is well-justified (whole-section as the atomic unit) and I’m glad it’s documented in NOTES rather than left implicit.

iODBC. This is the one I care most about, and your shared-package proposal is the right shape - moving odbcinst-generate + the triggers + drop-in dirs + the %ghost config into something both unixODBC and libiodbc depend on is exactly how you get the trigger to fire on iODBC-only hosts. One thing worth pinning down before you commit to layering: what is Conflicts: iodbc actually based on? If (as I suspect) it’s historical ownership of /etc/odbcinst.ini (and /etc/odbc.ini), then making odbcinst.ini %ghost and having a shared package own the drop-in dirs may let that Conflicts be retired entirely - i.e. the shared package doesn’t just fix trigger-firing, it enables genuine coexistence of both managers. That would be a strictly better outcome than “either/or,” and it’s the same shared package either way. If there’s a second reason for the conflict (a genuinely-shared binary or path), that’s worth surfacing now since it constrains the design.

Re-review: :+1: on the three landed items. The iODBC layering is the last piece; I think it can be more than a workaround.

Bare → absolute paths — both hardenings landed. odbcinst-generate now does per-driver existence-checked probing: for each bare .so name it checks /usr/lib64/odbc/ first, then /usr/lib/odbc/. If found, it rewrites to the absolute path.
If not found in either directory, the bare name is left unchanged. This handles both the third-party driver case (no rewrite to a non-existent path) and the multilib case (32-bit driver correctly resolves to /usr/lib/odbc/). Updated code and man page: unixODBC commit 90ec123.

Conflicts: iodbc — removed, it really was a dead no-op. The line dates to the very first spec import (unixODBC 1.8.12-2, year 2000). It targets the package name iodbc, but iODBC has been packaged as libiodbc for years with no Provides: iodbc
the Conflicts never actually fired. :slight_smile:
I verified there are zero file-level overlaps today: different sonames (libodbc.so.2 vs libiodbc.so.2), different binaries, namespaced headers (/usr/include/libiodbc/), different pkg-config, and libiodbc ships no config files at all. Co-installation verified clean in a Rawhide container. Separate commit on the branch: 97987f1.

Shared (sub?)package for odbcinst-generate
I moved the whole odbcinst-generate logic to a unixODBC-odbcinst-generate sub-package.
I left the migration logic in the main unixODBC sub-package (it owned the odbcinst.ini before, so should IMO be responsible for the migration)
I included the libiodbc package into the change set, adding a simple Requires: there.

It can be made a brand new separate package instead, but I’m not sure whether the benefits outweighs the additional work. What do you think?


Change text updated
COPR - full rebuild of all affected packages

Ready for re-review

On a multilib host shouldn’t it resolve the 64 bit driver into Driver64= and the 32 bit driver into Driver= so that both can work depending on the client? That’s how I currently have it setup in my hand written configuration…

Thanks Michal! The absolute-path probing and dropping the dead Conflicts: iodbc both look right.

On the shared package: I’d endorse the direction but tweak the naming and structure. Name. unixODBC-odbcinst-generate bakes in the wrong ownership. libiodbc: Requires: unixODBC-… is a dependency arrow pointing into unixODBC’s namespace for something that’s meant to be driver-manager-neutral - both DMs are equal consumers. The mental model here is hicolor-icon-theme / crypto-policies: a small neutral thing that owns shared dirs, and everyone drops into it.

Initially I was thinking about *-filesystem but in Fedora that suffix connotes directory ownership only, no payload (cf. httpd-filesystem), and this package ships the odbcinst-generate binary + file triggers + a man page. That’s active behavior, so let’s just name it after the tool: odbcinst-generate.

You don’t need a separate SRPM to get that name. %package -n odbcinst-generate drops the unixODBC- prefix while keeping it a subpackage of the unixODBC SRPM so no new-package review, no extra maintenance point, and libiodbc: Requires: odbcinst-generate reads cleanly. A cross-SRPM binary Requires is completely normal. The only thing wrong today is the name, and -n fixes exactly that. I’d only spin a genuinely separate SRPM if we want this substrate maintained independently of unixODBC’s release cadence which I don’t think buys us much right now.

Migration split by tense: keep the one-shot .rpmsave upgrade scriptlet in unixODBC (only it upgrades from the old broken state; iODBC never owned that file) - good call. But move the going-forward %ghost /etc/odbcinst.ini into odbcinst-generate, since that’s the thing that regenerates it. Then “who owns the file now” has an honest answer.

So: %package -n odbcinst-generate owning the drop-in dirs + the %ghost + the tool + triggers; unixODBC and libiodbc both Requires: it; the transitional migration stays in unixODBC. Happy to review once it’s in COPR.

Feedback addressed:

  • multilib Driver/Driver64 support
  • subpackage naming
  • migration ownership split

Extra fixes beyond the feedback:

  • made the sub-package noarch
  • GPL-2.0-or-later explicit licensing, matching unixODBC scripts, compatible with libiodbc
  • Trailing whitespace tolerance in the regex that matches bare library names — a snippet value like Driver = libmaodbc.so (trailing space) no longer defeats path resolution
  • Directory co-ownership across all 6 driver packages — each now has %dir %{_prefix}/lib/odbc and %dir %{_prefix}/lib/odbc/odbcinst.d, because of the need for snippet subdirectory separation — snippets go in odbcinst.d/ rather than directly in /usr/lib/odbc/ to prevent spurious file trigger fires when 32-bit driver .so files are installed
  • iODBC Driver64 limitation documented in the man page and Fedora Change wikitext — iODBC reads only Driver, ignores Driver64 harmlessly
  • All 8 packages rebased onto the F45 mass rebuild

Fedora Change wiki text updated
COPR - full rebuild of all affected packages

Ready for re-review

This change proposal has now been submitted to FESCo with ticket [#3655](Making sure you're not a bot!) for voting.

To find out more, please visit our [Changes Policy](Making sure you're not a bot!) documentation.

LGTM, thanks!

This change has been accepted by FESCo for Fedora Linux 45. A full list of approved changes to date can be found on the [Change Set Page](Releases/45/ChangeSet - Fedora Project Wiki).

To find out more about how our changes policy works, please visit our [docs site](Making sure you're not a bot!).