SERVICEFILE Shows Wrong File After Servicefile Fallback
Core Problem
This bug report identifies a logical inconsistency in libpq's service file resolution mechanism, specifically in how the SERVICEFILE connection parameter tracks which file actually provided the service definition.
The Service File Fallback Mechanism
libpq supports a two-tier service file lookup:
- Primary lookup: The file specified via the
servicefileconnection parameter (orPGSERVICEFILEenvironment variable) - Fallback lookup: If the requested service name is not found in the primary file, libpq falls back to the system-wide
pg_service.conf(located inPGSYSCONFDIR)
This fallback is implemented in parseServiceFile() within libpq's connection handling code.
The Bug: State Desynchronization
The issue arises from commit 092f3c63efc6, which introduced the SERVICEFILE connection option to expose which service file was used. The problem is a classic state synchronization bug:
- User specifies
servicefile=/tmp/svc/empty.confin the connection string - libpq stores this value in
connOptionsearly during connection parameter parsing parseServiceFile()is called with the specified file — the requested service is not found- libpq falls back to
$PGSYSCONFDIR/pg_service.conf— the service is found here - However,
parseServiceFile()checks whetherservicefileis already set in connection options, and if so, refuses to update it - Result:
connOptions.servicefilestill points to the original (empty) file, not the file that actually provided the service configuration
This means SERVICEFILE (exposed as a psql variable) reports a file that did not contain the service definition — a misleading and incorrect value.
Architectural Significance
This matters because:
- Debuggability: The entire purpose of exposing
SERVICEFILEas a psql variable is to help users understand which configuration file is active. Showing the wrong file defeats this purpose entirely. - Correctness of connection metadata: Applications relying on
PQconninfo()to inspect connection parameters would get incorrect information about the provenance of their service configuration. - Principle of least surprise: If a user sees
SERVICEFILE = /tmp/svc/empty.conf, they would expect that file to contain the[actual]service block, leading to confusion during troubleshooting.
Proposed Fix
The fix is straightforward: when the fallback path is taken (i.e., the service is found in pg_service.conf rather than the originally-specified service file), explicitly update the servicefile connection option to reflect the actual file that provided the service definition.
This ensures that:
parseServiceFile()always synchronizes the stored service file path with the file that actually matched- The
SERVICEFILEpsql variable andPQconninfo()output correctly reflect reality
Design Consideration
The original guard in parseServiceFile() — "if servicefile is already set, don't update" — was likely intended to preserve the user's explicitly-specified value. However, this logic is incorrect in the fallback scenario: once the fallback succeeds, the "actual" service file has changed, and the connection option should reflect the truth rather than the user's initial (unsuccessful) specification.
Affected Code Path
libpq/fe-connect.c → connectOptions2() → parseServiceInfo() → parseServiceFile()
The flow:
parseServiceFile(filename=user_specified_file, ...)→ service not found, returns without applying settingsparseServiceFile(filename=sysconf_file, ...)→ service found, applies settings but does NOT update theservicefileconnopt because it's already populated from step 1
The fix modifies step 2 to forcibly update servicefile when the fallback file successfully resolves the service.