various: add -Dbuild-static and alternatives to libc functions

When we try to build with -static, the linker refuses dlopen and
various functions related to nss. This commit adds the basic support
to compile with -static and allow the link to pass.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-07-02 17:19:18 +02:00
parent b3749de21c
commit bbeef4b948
7 changed files with 65 additions and 17 deletions
+2
View File
@@ -80,6 +80,8 @@ conf.set10('SD_BOOT', false)
conf.set10('SYSTEMD_MULTICALL_BINARY', get_option('systemd-multicall-binary'))
conf.set10('BUILD_STATIC', get_option('build-static'))
# Create a title-less summary section early, so it ends up first in the output.
# More items are added later after they have been detected.
summary({
+2
View File
@@ -42,6 +42,8 @@ option('static-libudev', type : 'combo',
description : 'install a static library for libudev')
option('standalone-binaries', type : 'boolean', value : false,
description : 'also build standalone versions of supported binaries')
option('build-static', type : 'boolean', value : false,
description : 'build static versions of supported binaries')
option('sysvinit-path', type : 'string', value : '/etc/init.d', deprecated : true,
description : 'This option is deprecated and will be removed in a future release')
+5
View File
@@ -101,6 +101,10 @@ void block_dlopen(void) {
}
int dlopen_safe(const char *filename, void **ret, const char **reterr_dlerror) {
#if BUILD_STATIC
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"dlopen is not supported in static builds, cannot load %s.", filename);
#else
_cleanup_(dlclosep) void *dl = NULL;
int r;
@@ -142,4 +146,5 @@ int dlopen_safe(const char *filename, void **ret, const char **reterr_dlerror) {
*ret = TAKE_PTR(dl);
return 0;
#endif
}
+43 -13
View File
@@ -1171,6 +1171,9 @@ int lookup_pwent_in_files(
return -ESRCH;
}
#if !BUILD_STATIC
static size_t getpw_buffer_size(void) {
long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
return bufsize <= 0 ? 4096U : (size_t) bufsize;
@@ -1182,15 +1185,25 @@ static bool errno_is_user_doesnt_exist(int error) {
return IN_SET(abs(error), ENOENT, ESRCH, EBADF, EPERM);
}
#endif
int getpwnam_malloc(const char *name, struct passwd **ret) {
/* For static builds use a very simplistic implementation that looks at 'passwd' in /etc/
* and /usr/lib/, and for non-static builds use NSS. The first matching entry wins. The
* same logic is implemented in getpwnam_malloc, getpwuid_malloc, getgrnam_malloc, and
* getgrgid_malloc. */
if (isempty(name))
return -EINVAL;
#if BUILD_STATIC
return lookup_pwent_in_files(PASSWD_FILES, name, UID_INVALID, ret);
#else
size_t bufsize = getpw_buffer_size();
int r;
/* A wrapper around getpwnam_r() that allocates the necessary buffer on the heap. The caller must
* free() the returned structures! */
if (isempty(name))
return -EINVAL;
* free() the returned structure! */
for (;;) {
_cleanup_free_ void *buf = NULL;
@@ -1226,15 +1239,19 @@ int getpwnam_malloc(const char *name, struct passwd **ret) {
return -ENOMEM;
bufsize *= 2;
}
#endif
}
int getpwuid_malloc(uid_t uid, struct passwd **ret) {
size_t bufsize = getpw_buffer_size();
int r;
if (!uid_is_valid(uid))
return -EINVAL;
#if BUILD_STATIC
return lookup_pwent_in_files(PASSWD_FILES, /* name= */ NULL, uid, ret);
#else
size_t bufsize = getpw_buffer_size();
int r;
for (;;) {
_cleanup_free_ void *buf = NULL;
@@ -1267,6 +1284,7 @@ int getpwuid_malloc(uid_t uid, struct passwd **ret) {
return -ENOMEM;
bufsize *= 2;
}
#endif
}
static int copy_struct_group(const struct group *gr, struct group **ret) {
@@ -1427,18 +1445,25 @@ ssize_t lookup_groups_in_files(
return n_arr;
}
#if !BUILD_STATIC
static size_t getgr_buffer_size(void) {
long bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
return bufsize <= 0 ? 4096U : (size_t) bufsize;
}
int getgrnam_malloc(const char *name, struct group **ret) {
size_t bufsize = getgr_buffer_size();
int r;
#endif
int getgrnam_malloc(const char *name, struct group **ret) {
if (isempty(name))
return -EINVAL;
#if BUILD_STATIC
return lookup_grent_in_files(GROUP_FILES, name, GID_INVALID, ret);
#else
size_t bufsize = getgr_buffer_size();
int r;
for (;;) {
_cleanup_free_ void *buf = NULL;
@@ -1471,15 +1496,19 @@ int getgrnam_malloc(const char *name, struct group **ret) {
return -ENOMEM;
bufsize *= 2;
}
#endif
}
int getgrgid_malloc(gid_t gid, struct group **ret) {
size_t bufsize = getgr_buffer_size();
int r;
if (!gid_is_valid(gid))
return -EINVAL;
#if BUILD_STATIC
return lookup_grent_in_files(GROUP_FILES, /* name= */ NULL, gid, ret);
#else
size_t bufsize = getgr_buffer_size();
int r;
for (;;) {
_cleanup_free_ void *buf = NULL;
@@ -1512,4 +1541,5 @@ int getgrgid_malloc(gid_t gid, struct group **ret) {
return -ENOMEM;
bufsize *= 2;
}
#endif
}
+4
View File
@@ -159,6 +159,10 @@ static inline bool hashed_password_is_locked_or_invalid(const char *password) {
return password && password[0] != '$';
}
/* Places where we will try to load account data from */
#define PASSWD_FILES STRV_MAKE("/etc/passwd", "/usr/lib/passwd")
#define GROUP_FILES STRV_MAKE("/etc/group", "/usr/lib/group")
/* A locked *and* invalid password for "struct spwd"'s .sp_pwdp and "struct passwd"'s .pw_passwd field */
#define PASSWORD_LOCKED_AND_INVALID "!*"
+5
View File
@@ -827,6 +827,10 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
}
static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
#if BUILD_STATIC
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"tcp:// connections are not supported in static builds");
#else
_cleanup_free_ char *host = NULL, *port = NULL, *family = NULL;
int r;
struct addrinfo *result, hints = {
@@ -889,6 +893,7 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
b->is_local = false;
return 0;
#endif
}
static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
+4 -4
View File
@@ -53,10 +53,10 @@ static int populate_uid_cache(const char *root, Hashmap **ret) {
/* The directory list is hardcoded here: /etc is the standard, and rpm-ostree uses /usr/lib. This
* could be made configurable, but I don't see the point right now. */
FOREACH_STRING(fname, "/etc/passwd", "/usr/lib/passwd") {
STRV_FOREACH(fname, PASSWD_FILES) {
_cleanup_fclose_ FILE *f = NULL;
r = open_passwd_file(root, fname, &f);
r = open_passwd_file(root, *fname, &f);
if (r == -ENOENT)
continue;
if (r < 0)
@@ -93,10 +93,10 @@ static int populate_gid_cache(const char *root, Hashmap **ret) {
if (!cache)
return -ENOMEM;
FOREACH_STRING(fname, "/etc/group", "/usr/lib/group") {
STRV_FOREACH(fname, GROUP_FILES) {
_cleanup_fclose_ FILE *f = NULL;
r = open_passwd_file(root, fname, &f);
r = open_passwd_file(root, *fname, &f);
if (r == -ENOENT)
continue;
if (r < 0)