This patch reinstates support for static NSS, which glibc 2.33 broke: https://sourceware.org/bugzilla/show_bug.cgi?id=27959 Patch obtained by running: git diff f0c28504a9877be5da3ed1215f2da2d5914bbb0b..f9c8b11ed7726b858cd7b7cea0d3d7c5233d78cf git diff 5e1ce61e3e71fb7ffe53f58fe96e67cb15f94854{^,} git diff 135425a1dd50cbe2b9db0628d6c2b36c7889f30b{^,} It corresponds to these changes: f9c8b11ed7 * nss: Access nss_files through direct references 6212bb67f4 * nss_files: Move into libc 36861a968a * nss_files: Add generic code for set*ent, end*ent and file open f0c28504a9 * nss_files: Allocate nscd file registration data on the heap 5e1ce61e3e * nss: Fix NSS_DECLARE_MODULE_FUNCTIONS handling of _nss_*_endnetgrent 135425a1dd * nss: Fix build error with --disable-nscd ... plus a manual fix in 'files-network.c' to address this compilation error: nss_files/files-network.c: In function ‘_nss_files_parse_netent’: nss_files/files-network.c:72:20: error: implicit declaration of function ‘__inet_network’; did you mean ‘inet_network’? [-Werror=implicit-function-declaration] 72 | result->n_net = __inet_network (addr); | ^~~~~~~~~~~~~~ nss_files/files-parse.c:106:3: note: in definition of macro ‘LINE_PARSER’ 106 | BODY; \ | ^~~~ diff --git a/include/libc-symbols.h b/include/libc-symbols.h index 127ea656c2..d41ecf4384 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -798,29 +798,6 @@ for linking") # define libdl_hidden_data_ver(local, name) #endif -#if IS_IN (libnss_files) -# define libnss_files_hidden_proto(name, attrs...) hidden_proto (name, ##attrs) -# define libnss_files_hidden_tls_proto(name, attrs...) \ - hidden_tls_proto (name, ##attrs) -# define libnss_files_hidden_def(name) hidden_def (name) -# define libnss_files_hidden_weak(name) hidden_weak (name) -# define libnss_files_hidden_ver(local, # GNU Guix --- Functional package management for GNU # Copyright © 2014-2022, 2024 Ludovic Courtès <ludo@gnu.org> # Copyright © 2017 Tobias Geerinckx-Rice <me@tobias.gr> # Copyright © 2018 Chris Marusich <cmmarusich@gmail.com> # # This file is part of GNU Guix. # # GNU Guix is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or (at # your option) any later version. # # GNU Guix is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. # # Test 'guix system', mostly error reporting. # set -e guix system --version tmpfile="t-guix-system-$$" errorfile="t-guix-system-error-$$" # Note: This directory is chosen outside $builddir so that relative file name # canonicalization doesn't mess up with 'current-source-directory', used by # 'local-file' ('load' forces 'relative' for # %FILE-PORT-NAME-CANONICALIZATION.) tmpdir="${TMPDIR:-/tmp}/t-guix-system-$$" mkdir "$tmpdir" trap 'rm -f "$tmpfile" "$errorfile" "$tmpdir"/*; rmdir "$tmpdir"' EXIT # Reporting of syntax errors. cat > "$tmpfile"<<EOF ;; This is line 1, and the next one is line 2. (operating-system) ;; The 'T' is at column 3. EOF if guix system vm "$tmpfile" 2> "$errorfile" then # This must not succeed. exit 1 else cat "$errorfile" grep "$tmpfile:2:3:.*missing.* initializers" "$errorfile" fi cat > "$tmpfile"<<EOF ;; This is line 1, and the next one is line 2. (operating-system ;; This is line 3, and there is no closing paren! EOF if guix system vm "$tmpfile" 2> "$errorfile" then # This must not succeed. exit 1 else cat "$errorfile" # Guile 3.0.6 gets line/column numbers for 'read-error' wrong # (zero-indexed): <https://bugs.gnu.org/48089>. grep "$tmpfile:4:1: missing closing paren" "$errorfile" || \ grep "$tmpfile:3:0: missing closing paren" "$errorfile" fi # Reporting of module not found errors. cat > "$tmpfile" <<EOF ;; Line 1. (use-modules (gnu)) (use-service-modules openssh) EOF if guix system build "$tmpfile" -n 2> "$errorfile" then false else grep "$tmpfile:3:2: .*module .*openssh.*not found" "$errorfile" grep "Try.*use-service-modules ssh" "$errorfile" fi cat > "$tmpfile" <<EOF ;; Line 1. (use-modules (gnu)) (use-package-modules qemu) EOF if guix system build "$tmpfile" -n 2> "$errorfile" then false else grep "$tmpfile:3:2: .*module .*qemu.*not found" "$errorfile" grep "Try.*use-package-modules virtualization" "$errorfile" fi # Reporting of unbound variables. cat > "$tmpfile" <<EOF (use-modules (gnu)) ; 1 (use-service-modules networking) ; 2 (operating-system ; 4 (host-name "antelope") ; 5 (timezone "Europe/Paris") ; 6 (locale "en_US.UTF-8") ; 7 (bootloader (GRUB-config (targets (list "/dev/sdX")))) ; 9 (file-systems (cons (file-system (device (file-system-label "root")) (mount-point "/") (type "ext4")) %base-file-systems))) EOF if guix system build "$tmpfile" -n 2> "$errorfile" then false else if test "`guile -c '(display (effective-version))'`" = 3.0 then # FIXME: With Guile 3.3.0 the error is reported on line 11. # See <https://bugs.gnu.org/38388>. grep "$tmpfile:[0-9]\+:[0-9]\+:.*GRUB-config.*[Uu]nbound variable" "$errorfile" elif test "`guile -c '(display (effective-version))'`" = 2.2 then # FIXME: With Guile 2.2.0 the error is reported on line 4. # See <http://bugs.gnu.org/26107>. grep "$tmpfile:[49]:[0-9]\+:.*GRUB-config.*[Uu]nbound variable" "$errorfile" else grep "$tmpfile:9:[0-9]\+:.*GRUB-config.*[Uu]nbound variable" "$errorfile" fi fi cat > "$tmpfile" <<EOF (use-modules (gnu)) ; 1 (operating-system ; 3 (file-systems (cons (file-system ; 4 (device (file-system-label "root")) (mount-point "/") ; 6 (type "ext4")))) ; 7 (!!) %base-file-systems) EOF if guix system build "$tmpfile" -n 2> "$errorfile" then false else # Here '%base-file-systems' appears as if it were a field specified of the # enclosing 'operating-system' form due to parenthesis mismatch. grep "$tmpfile:3:[0-9]\+:.*%base-file-system.*invalid field specifier" \ "$errorfile" fi OS_BASE=' (host-name "antelope") (timezone "Europe/Paris") (locale "en_US.UTF-8") (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets (list "/dev/sdX")))) (file-systems (cons (file-system (device (file-system-label "root")) (mount-point "/") (type "ext4")) %base-file-systems)) ' # Reporting of duplicate service identifiers. cat > "$tmpfile" <<EOF (use-modules (gnu)) (use-service-modules networking) (operating-system $OS_BASE (services (cons* (service dhcp-client-service-type) (service dhcp-client-service-type) ;twice! %base-services))) EOF if guix system vm "$tmpfile" 2> "$errorfile" then # This must not succeed. exit 1 else grep "service 'networking'.*more than once" "$errorfile" fi # Reporting unmet shepherd requirements. cat > "$tmpfile" <<EOF (use-modules (gnu) (gnu services shepherd)) (use-service-modules networking) (define buggy-service-type (shepherd-service-type 'buggy (lambda _ (shepherd-service (provision '(buggy!)) (requirement '(does-not-exist)) (start #t))) (description "Buggy."))) (operating-system $OS_BASE (services (cons (service buggy-service-type #t) %base-services))) EOF if guix system build "$tmpfile" 2> "$errorfile" then exit 1 else grep "service 'buggy!'.*'does-not-exist'.*not provided" "$errorfile" fi # Reporting inconsistent user accounts. make_user_config () { cat > "$tmpfile" <<EOF (use-modules (gnu)) (use-service-modules networking) (operating-system (host-name "antelope") (timezone "Europe/Paris") (locale "en_US.UTF-8") (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets (list "/dev/sdX")))) (file-systems (cons (file-system (device (file-system-label "root")) (mount-point "/") (type "ext4")) %base-file-systems)) (users (list (user-account (name "dave") (home-directory "/home/dave") (group "$1") (supplementary-groups '("$2")))))) EOF } make_user_config "users" "wheel" guix system build "$tmpfile" -n # succeeds guix system build "$tmpfile" -d # succeeds guix system build "$tmpfile" -d | grep '\.drv$' guix system vm "$tmpfile" -d # succeeds guix system vm "$tmpfile" -d | grep '\.drv$' # Make sure the behavior is deterministic (<https://bugs.gnu.org/32652>). drv1="`guix system vm "$tmpfile" -d`" drv2="`guix system vm "$tmpfile" -d`" test "$drv1" = "$drv2" drv1="`guix system image -t iso9660 "$tmpfile" -d`" drv2="`guix system image -t iso9660 "$tmpfile" -d`" test "$drv1" = "$drv2" # Check whether the graph commands work as expected. guix system extension-graph "$tmpfile" | grep 'label = "file-systems"' guix system shepherd-graph "$tmpfile" | grep 'label = "guix-daemon"' make_user_config "group-that-does-not-exist" "users" if guix system build "$tmpfile" -n 2> "$errorfile" then false else grep "primary group.*group-that-does-not-exist.*undeclared" "$errorfile"; fi make_user_config "users" "group-that-does-not-exist" if guix system build "$tmpfile" -n 2> "$errorfile" then false else grep "supplementary group.*group-that-does-not-exist.*undeclared" "$errorfile"; fi # Try 'local-file' and relative file name resolution. cat > "$tmpdir/config.scm"<<EOF (use-modules (gnu)) (use-service-modules networking) (operating-system $OS_BASE (services (cons (service tor-service-type (tor-configuration (config-file (local-file "my-torrc")))) %base-services))) EOF cat > "$tmpdir/my-torrc"<<EOF # This is an example file. EOF # In both cases 'my-torrc' should be properly resolved. guix system build "$tmpdir/config.scm" -n (cd "$tmpdir"; guix system build "config.scm" -n) # Check that we get a warning when passing 'local-file' a non-literal relative # file name. cat > "$tmpdir/config.scm" <<EOF (use-modules (guix)) (define (bad-local-file file) (local-file file)) (bad-local-file "whatever.scm") EOF guix system build "$tmpdir/config.scm" -n && false guix system build "$tmpdir/config.scm" -n 2>&1 | \ grep "config\.scm:4:2: warning:.*whatever.*relative to current directory" # Searching. guix system search tor | grep "^name: tor" guix system search tor | grep "^shepherdnames: tor" guix system search anonym network | grep "^name: tor" guix system search . > "$tmpdir/search" test $(wc -l < "$tmpdir/search") -gt 500 rm "$tmpdir/search" # Below, use -n (--dry-run) for the tests because if we actually tried to # build these images, the commands would take hours to run in the worst case. # Verify that the examples can be built. for example in gnu/system/examples/*.tmpl; do case "$example" in *hurd*) options="--target=i586-pc-gnu";; *asus*) # 'asus-c201.tmpl' uses 'linux-libre-arm-generic', which is an # ARM-only package. options="--system=armhf-linux";; *raspberry*) # The Raspberry Pi templates 'linux-libre-arm64-generic', which is # an ARM-only package. options="--system=aarch64-linux";; *plasma*) # Some architectures do not support all the packages Plasma # depends on so restrict to x86_64-linux. options="--system=x86_64-linux";; *vm-image*) # The VM image tries to build 'current-guix' as per 'guix pull'. # Skip it. continue ;; *desktop*) # This image uses 'grub-efi-bootloader' so it needs a GPT # partition. options="-t efi-raw --system=x86_64-linux";; *) options="" ;; esac guix system -n image $options "$example" done # Make sure the desktop image can be built on major architectures. for system in x86_64-linux aarch64-linux do guix system -n image -s "$system" -t efi-raw \ gnu/system/examples/desktop.tmpl done # Verify that the images can be built. guix system -n vm gnu/system/examples/bare-bones.tmpl guix system -n image gnu/system/images/pinebook-pro.scm guix system -n image -t qcow2 gnu/system/examples/bare-bones.tmpl guix system -n image -t iso9660 gnu/system/examples/bare-bones.tmpl guix system -n docker-image gnu/system/examples/docker-image.tmpl # Verify that at least the raw image type is available. guix system --list-image-types | grep "raw" * Nothing to read. */ break; @@ -220,7 +187,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, /* If the file does not exist we simply ignore the statement. */ if (listfile != NULL - && (old_line = strdup (line)) != NULL) + && (old_line = __strdup (line)) != NULL) { while (! feof_unlocked (listfile)) { @@ -232,8 +199,8 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, } first_unused[room_left - 1] = '\xff'; - line = fgets_unlocked (first_unused, room_left, - listfile); + line = __fgets_unlocked (first_unused, room_left, + listfile); if (line == NULL) break; if (first_unused[room_left - 1] != '\xff') @@ -335,7 +302,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result, /* The just read character is a white space and so can be ignored. */ first_unused[room_left - 1] = '\xff'; - line = fgets_unlocked (first_unused, room_left, stream); + line = __fgets_unlocked (first_unused, room_left, stream); if (line == NULL) { /* Continuation line without any data and @@ -369,29 +336,25 @@ _nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen, int *errnop) { /* Return next entry in host file. */ - enum nss_status status = NSS_STATUS_SUCCESS; - __libc_lock_lock (lock); - - /* Be prepared that the set*ent function was not called before. */ - if (stream == NULL) - status = internal_setent (&stream); - - if (status == NSS_STATUS_SUCCESS) - { - result->alias_local = 1; + struct nss_files_per_file_data *data; + enum nss_status status = __nss_files_data_open (&data, nss_file_aliasent, + "/etc/aliases", errnop, NULL); + if (status != NSS_STATUS_SUCCESS) + return status; - /* Read lines until we get a definite result. */ - do - status = get_next_alias (stream, NULL, result, buffer, buflen, errnop); - while (status == NSS_STATUS_RETURN); - } + result->alias_local = 1; - __libc_lock_unlock (lock); + /* Read lines until we get a definite result. */ + do + status = get_next_alias (data->stream, NULL, result, buffer, buflen, + errnop); + while (status == NSS_STATUS_RETURN); + __nss_files_data_put (data); return status; } - +libc_hidden_def (_nss_files_getaliasent_r) enum nss_status _nss_files_getaliasbyname_r (const char *name, struct aliasent *result, @@ -418,9 +381,10 @@ _nss_files_getaliasbyname_r (const char *name, struct aliasent *result, do status = get_next_alias (stream, name, result, buffer, buflen, errnop); while (status == NSS_STATUS_RETURN); - } - internal_endent (&stream); + fclose (stream); + } return status; } +libc_hidden_def (_nss_files_getaliasbyname_r) diff --git a/nss/nss_files/files-ethers.c b/nss/nss_files/files-ethers.c index 2fe7f81e4b..7c2c2b9833 100644 --- a/nss/nss_files/files-ethers.c +++ b/nss/nss_files/files-ethers.c @@ -20,8 +20,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - struct etherent_data {}; #define ENTNAME etherent diff --git a/nss/nss_files/files-grp.c b/nss/nss_files/files-grp.c index 49be38e8b1..a716d948e2 100644 --- a/nss/nss_files/files-grp.c +++ b/nss/nss_files/files-grp.c @@ -19,8 +19,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define STRUCTURE group #define ENTNAME grent #define DATABASE "group" diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c index 2b47ec3e53..d54d91d038 100644 --- a/nss/nss_files/files-hosts.c +++ b/nss/nss_files/files-hosts.c @@ -26,8 +26,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - /* Get implementation for some internal functions. */ #include "../resolv/res_hconf.h" @@ -57,12 +55,13 @@ LINE_PARSER STRING_FIELD (addr, isspace, 1); /* Parse address. */ - if (inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr) + if (__inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr) > 0) af = af == AF_UNSPEC ? AF_INET : af; else { - if (af == AF_INET && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + if (af == AF_INET + && __inet_pton (AF_INET6, addr, entdata->host_addr) > 0) { if (IN6_IS_ADDR_V4MAPPED (entdata->host_addr)) memcpy (entdata->host_addr, entdata->host_addr + 12, INADDRSZ); @@ -76,7 +75,7 @@ LINE_PARSER return 0; } else if (af == AF_UNSPEC - && inet_pton (AF_INET6, addr, entdata->host_addr) > 0) + && __inet_pton (AF_INET6, addr, entdata->host_addr) > 0) af = AF_INET6; else /* Illegal address: ignore line. */ @@ -349,7 +348,7 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result, status = gethostbyname3_multi (stream, name, af, result, buffer, buflen, errnop, herrnop); - internal_endent (&stream); + fclose (stream); } if (canonp && status == NSS_STATUS_SUCCESS) @@ -357,6 +356,7 @@ _nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result, return status; } +libc_hidden_def (_nss_files_gethostbyname3_r) enum nss_status _nss_files_gethostbyname_r (const char *name, struct hostent *result, @@ -366,6 +366,7 @@ _nss_files_gethostbyname_r (const char *name, struct hostent *result, return _nss_files_gethostbyname3_r (name, AF_INET, result, buffer, buflen, errnop, herrnop, NULL, NULL); } +libc_hidden_def (_nss_files_gethostbyname_r) enum nss_status _nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result, @@ -375,6 +376,7 @@ _nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result, return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen, errnop, herrnop, NULL, NULL); } +libc_hidden_def (_nss_files_gethostbyname2_r) enum nss_status _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, @@ -475,7 +477,7 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, status = NSS_STATUS_SUCCESS; } - internal_endent (&stream); + fclose (stream); } else if (status == NSS_STATUS_TRYAGAIN) { @@ -490,3 +492,4 @@ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, return status; } +libc_hidden_def (_nss_files_gethostbyname4_r) diff --git a/nss/nss_files/files-init.c b/nss/nss_files/files-init.c index 717c9fd334..18ed288d04 100644 --- a/nss/nss_files/files-init.c +++ b/nss/nss_files/files-init.c @@ -21,8 +21,7 @@ #include #include #include - -NSS_DECLARE_MODULE_FUNCTIONS (files) +#include static void register_file (void (*cb) (size_t, struct traced_file *), @@ -49,5 +48,6 @@ _nss_files_init (void (*cb) (size_t, struct traced_file *)) register_file (cb, servdb, "/etc/services", 0); register_file (cb, netgrdb, "/etc/netgroup", 0); } +libc_hidden_def (_nss_files_init) #endif diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c index 6fcea40b55..b44211e50b 100644 --- a/nss/nss_files/files-initgroups.c +++ b/nss/nss_files/files-initgroups.c @@ -28,8 +28,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - enum nss_status _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, @@ -129,3 +127,4 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start, return status == NSS_STATUS_SUCCESS && !any ? NSS_STATUS_NOTFOUND : status; } +libc_hidden_def (_nss_files_initgroups_dyn) diff --git a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c index f8c821c2f0..75bfbd9e44 100644 --- a/nss/nss_files/files-netgrp.c +++ b/nss/nss_files/files-netgrp.c @@ -28,11 +28,9 @@ #include "netgroup.h" #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define DATAFILE "/etc/netgroup" -libnss_files_hidden_proto (_nss_files_endnetgrent) +libc_hidden_proto (_nss_files_endnetgrent) #define EXPAND(needed) \ do \ @@ -152,7 +150,7 @@ _nss_files_setnetgrent (const char *group, struct __netgrent *result) return status; } - +libc_hidden_def (_nss_files_setnetgrent) enum nss_status _nss_files_endnetgrent (struct __netgrent *result) @@ -164,7 +162,7 @@ _nss_files_endnetgrent (struct __netgrent *result) result->cursor = NULL; return NSS_STATUS_SUCCESS; } -libnss_files_hidden_def (_nss_files_endnetgrent) +libc_hidden_def (_nss_files_endnetgrent) static char * strip_whitespace (char *str) @@ -279,7 +277,7 @@ _nss_netgroup_parseline (char **cursor, struct __netgrent *result, return status; } -libnss_files_hidden_def (_nss_netgroup_parseline) +libc_hidden_def (_nss_netgroup_parseline) enum nss_status @@ -293,3 +291,4 @@ _nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, return status; } +libc_hidden_def (_nss_files_getnetgrent_r) diff --git a/nss/nss_files/files-network.c b/nss/nss_files/files-network.c index 9cd7d7dc79..217ed78609 100644 --- a/nss/nss_files/files-network.c +++ b/nss/nss_files/files-network.c @@ -22,8 +22,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define ENTNAME netent #define DATABASE "networks" #define NEED_H_ERRNO @@ -71,7 +69,7 @@ LINE_PARSER *cp = '\0'; addr = newp; } - result->n_net = inet_network (addr); + result->n_net = inet_network (addr); result->n_addrtype = AF_INET; }) diff --git a/nss/nss_files/files-parse.c b/nss/nss_files/files-parse.c index 68c51c7cbf..997eac573a 100644 --- a/nss/nss_files/files-parse.c +++ b/nss/nss_files/files-parse.c @@ -74,13 +74,7 @@ struct parser_data /* Export the line parser function so it can be used in nss_db. */ # define parser_stclass /* Global */ # define parse_line CONCAT(_nss_files_parse_,ENTNAME) -# if IS_IN (libc) -/* We are defining one of the functions that actually lives in libc - because it is used to implement fget*ent and suchlike. */ -# define nss_files_parse_hidden_def(name) libc_hidden_def (name) -# else -# define nss_files_parse_hidden_def(name) libnss_files_hidden_def (name) -# endif +# define nss_files_parse_hidden_def(name) libc_hidden_def (name) #endif diff --git a/nss/nss_files/files-proto.c b/nss/nss_files/files-proto.c index 98d082c642..13072692c1 100644 --- a/nss/nss_files/files-proto.c +++ b/nss/nss_files/files-proto.c @@ -19,8 +19,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define ENTNAME protoent #define DATABASE "protocols" diff --git a/nss/nss_files/files-pwd.c b/nss/nss_files/files-pwd.c index b04165ddde..5c74c6da9b 100644 --- a/nss/nss_files/files-pwd.c +++ b/nss/nss_files/files-pwd.c @@ -19,8 +19,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define STRUCTURE passwd #define ENTNAME pwent #define DATABASE "passwd" diff --git a/nss/nss_files/files-rpc.c b/nss/nss_files/files-rpc.c index eeb2725d2c..3dea8f18f2 100644 --- a/nss/nss_files/files-rpc.c +++ b/nss/nss_files/files-rpc.c @@ -19,8 +19,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define ENTNAME rpcent #define DATABASE "rpc" diff --git a/nss/nss_files/files-service.c b/nss/nss_files/files-service.c index f4f0985377..a8d83e094e 100644 --- a/nss/nss_files/files-service.c +++ b/nss/nss_files/files-service.c @@ -20,8 +20,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define ENTNAME servent #define DATABASE "services" diff --git a/nss/nss_files/files-sgrp.c b/nss/nss_files/files-sgrp.c index 6b1c9eac02..213a408e7b 100644 --- a/nss/nss_files/files-sgrp.c +++ b/nss/nss_files/files-sgrp.c @@ -19,8 +19,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define STRUCTURE sgrp #define ENTNAME sgent #define DATABASE "gshadow" diff --git a/nss/nss_files/files-spwd.c b/nss/nss_files/files-spwd.c index 976deaf918..d031257a20 100644 --- a/nss/nss_files/files-spwd.c +++ b/nss/nss_files/files-spwd.c @@ -19,8 +19,6 @@ #include #include -NSS_DECLARE_MODULE_FUNCTIONS (files) - #define STRUCTURE spwd #define ENTNAME spent #define DATABASE "shadow" diff --git a/nss/nss_files_data.c b/nss/nss_files_data.c new file mode 100644 index 0000000000..80fbfe5fff --- /dev/null +++ b/nss/nss_files_data.c @@ -0,0 +1,161 @@ +/* Returns a pointer to the global nss_files data structure. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +/* This collects all per file-data. */ +struct nss_files_data +{ + struct nss_files_per_file_data files[nss_file_count]; +}; + +/* For use with allocate_once. */ +static void *nss_files_global; +static void * +nss_files_global_allocate (void *closure) +{ + struct nss_files_data *result = malloc (sizeof (*result)); + if (result != NULL) + { + for (int i = 0; i < nss_file_count; ++i) + { + result->files[i].stream = NULL; + __libc_lock_init (result->files[i].lock); + } + } + return result; +} +/* Like __nss_files_data_open, but does not perform the open call. */ +static enum nss_status +__nss_files_data_get (struct nss_files_per_file_data **pdata, + enum nss_files_file file, int *errnop, int *herrnop) +{ + struct nss_files_data *data = allocate_once (&nss_files_global, + nss_files_global_allocate, + NULL, NULL); + if (data == NULL) + { + if (errnop != NULL) + *errnop = errno; + if (herrnop != NULL) + { + __set_h_errno (NETDB_INTERNAL); + *herrnop = NETDB_INTERNAL; + } + return NSS_STATUS_TRYAGAIN; + } + + *pdata = &data->files[file]; + __libc_lock_lock ((*pdata)->lock); + return NSS_STATUS_SUCCESS; +} + +/* Helper function for opening the backing file at PATH. */ +static enum nss_status +__nss_files_data_internal_open (struct nss_files_per_file_data *data, + const char *path) +{ + enum nss_status status = NSS_STATUS_SUCCESS; + + if (data->stream == NULL) + { + data->stream = __nss_files_fopen (path); + + if (data->stream == NULL) + status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + } + + return status; +} + + +enum nss_status +__nss_files_data_open (struct nss_files_per_file_data **pdata, + enum nss_files_file file, const char *path, + int *errnop, int *herrnop) +{ + enum nss_status status = __nss_files_data_get (pdata, file, errnop, herrnop); + if (status != NSS_STATUS_SUCCESS) + return status; + + /* Be prepared that the set*ent function was not called before. */ + if ((*pdata)->stream == NULL) + { + int saved_errno = errno; + status = __nss_files_data_internal_open (*pdata, path); + __set_errno (saved_errno); + if (status != NSS_STATUS_SUCCESS) + __nss_files_data_put (*pdata); + } + + return status; +} + +libc_hidden_def (__nss_files_data_open) + +void +__nss_files_data_put (struct nss_files_per_file_data *data) +{ + __libc_lock_unlock (data->lock); +} +libc_hidden_def (__nss_files_data_put) + +enum nss_status +__nss_files_data_setent (enum nss_files_file file, const char *path) +{ + struct nss_files_per_file_data *data; + enum nss_status status = __nss_files_data_get (&data, file, NULL, NULL); + if (status != NSS_STATUS_SUCCESS) + return status; + + if (data->stream == NULL) + status = __nss_files_data_internal_open (data, path); + else + rewind (data->stream); + + __nss_files_data_put (data); + return status; +} +libc_hidden_def (__nss_files_data_setent) + +enum nss_status +__nss_files_data_endent (enum nss_files_file file) +{ + /* No cleanup is necessary if not initialized. */ + struct nss_files_data *data = atomic_load_acquire (&nss_files_global); + if (data == NULL) + return NSS_STATUS_SUCCESS; + + struct nss_files_per_file_data *fdata = &data->files[file]; + __libc_lock_lock (fdata->lock); + if (fdata->stream != NULL) + { + fclose (fdata->stream); + fdata->stream = NULL; + } + __libc_lock_unlock (fdata->lock); + + return NSS_STATUS_SUCCESS; +} +libc_hidden_def (__nss_files_data_endent) diff --git a/nss/nss_files_functions.c b/nss/nss_files_functions.c new file mode 100644 index 0000000000..85720b4311 --- /dev/null +++ b/nss/nss_files_functions.c @@ -0,0 +1,43 @@ +/* Direct access for nss_files functions for NSS module loading. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void +__nss_files_functions (nss_module_functions_untyped pointers) +{ + void **fptr = pointers; + + /* Functions which are not implemented. */ +#define _nss_files_getcanonname_r NULL +#define _nss_files_gethostbyaddr2_r NULL +#define _nss_files_getpublickey NULL +#define _nss_files_getsecretkey NULL +#define _nss_files_netname2user NULL + +#undef DEFINE_NSS_FUNCTION +#define DEFINE_NSS_FUNCTION(x) *fptr++ = _nss_files_##x; +#include "function.def" + +#ifdef PTR_MANGLE + void **end = fptr; + for (fptr = pointers; fptr != end; ++fptr) + PTR_MANGLE (*fptr); +#endif +} diff --git a/nss/nss_module.c b/nss/nss_module.c index 60c070c851..7b42c585a4 100644 --- a/nss/nss_module.c +++ b/nss/nss_module.c @@ -30,6 +30,7 @@ #include #include #include +#include /* Suffix after .so of NSS service modules. This is a bit of magic, but we assume LIBNSS_FILES_SO looks like "libnss_files.so.2" and we @@ -110,10 +111,45 @@ static const function_name nss_function_name_array[] = #include "function.def" }; +static bool +module_load_nss_files (struct nss_module *module) +{ + if (is_nscd) + { + void (*cb) (size_t, struct traced_file *) = nscd_init_cb; +# ifdef PTR_DEMANGLE + PTR_DEMANGLE (cb); +# endif + _nss_files_init (cb); + } + + /* Initialize the function pointers, following the double-checked + locking idiom. */ + __libc_lock_lock (nss_module_list_lock); + switch ((enum nss_module_state) atomic_load_acquire (&module->state)) + { + case nss_module_uninitialized: + case nss_module_failed: + __nss_files_functions (module->functions.untyped); + module->handle = NULL; + /* Synchronizes with unlocked __nss_module_load atomic_load_acquire. */ + atomic_store_release (&module->state, nss_module_loaded); + break; + case nss_module_loaded: + /* Nothing to clean up. */ + break; + } + __libc_lock_unlock (nss_module_list_lock); + return true; +} + /* Internal implementation of __nss_module_load. */ static bool module_load (struct nss_module *module) { + if (strcmp (module->name, "files") == 0) + return module_load_nss_files (module); + void *handle; { char *shlib_name; @@ -360,7 +396,7 @@ __nss_module_freeres (void) struct nss_module *current = nss_module_list; while (current != NULL) { - if (current->state == nss_module_loaded) + if (current->state == nss_module_loaded && current->handle != NULL) __libc_dlclose (current->handle); struct nss_module *next = current->next; diff --git a/nss/nss_module.h b/nss/nss_module.h index 05c4791d11..c1a1d90b60 100644 --- a/nss/nss_module.h +++ b/nss/nss_module.h @@ -38,6 +38,10 @@ struct nss_module_functions typedef void *nss_module_functions_untyped[sizeof (struct nss_module_functions) / sizeof (void *)]; +/* Locate the nss_files functions, as if by dlopen/dlsym. */ +void __nss_files_functions (nss_module_functions_untyped pointers) + attribute_hidden; + /* Initialization state of a NSS module. */ enum nss_module_state { diff --git a/nss/nss_readline.c b/nss/nss_readline.c index 4b3ecbccc8..a2f397a11f 100644 --- a/nss/nss_readline.c +++ b/nss/nss_readline.c @@ -40,7 +40,7 @@ __nss_readline (FILE *fp, char *buf, size_t len, off64_t *poffset) *poffset = __ftello64 (fp); buf[len - 1] = '\xff'; /* Marker to recognize truncation. */ - if (fgets_unlocked (buf, len, fp) == NULL) + if (__fgets_unlocked (buf, len, fp) == NULL) { if (feof_unlocked (fp)) { @@ -61,7 +61,7 @@ __nss_readline (FILE *fp, char *buf, size_t len, off64_t *poffset) line on the next call. */ return __nss_readline_seek (fp, *poffset); - /* fgets_unlocked succeeded. */ + /* __fgets_unlocked succeeded. */ /* Remove leading whitespace. */ char *p = buf; diff --git a/nss/nss.h b/nss/nss.h index ae213f9a6c..c6d62adc0f 100644 --- a/nss/nss.h +++ b/nss/nss.h @@ -196,7 +196,7 @@ typedef enum nss_status nss_setspent (int); extern nss_endgrent _nss_##module##_endgrent; \ extern nss_endhostent _nss_##module##_endhostent; \ extern nss_endnetent _nss_##module##_endnetent; \ - extern nss_endnetgrent _nss_##module##__endnetgrent; \ + extern nss_endnetgrent _nss_##module##_endnetgrent; \ extern nss_endprotoent _nss_##module##_endprotoent; \ extern nss_endpwent _nss_##module##_endpwent; \ extern nss_endrpcent _nss_##module##_endrpcent; \ diff --git a/nss/nss_module.c b/nss/nss_module.c index 7b42c585a4..7ea5ad9887 100644 --- a/nss/nss_module.c +++ b/nss/nss_module.c @@ -114,14 +114,16 @@ static const function_name nss_function_name_array[] = static bool module_load_nss_files (struct nss_module *module) { +#ifdef USE_NSCD if (is_nscd) { void (*cb) (size_t, struct traced_file *) = nscd_init_cb; -# ifdef PTR_DEMANGLE +# ifdef PTR_DEMANGLE PTR_DEMANGLE (cb); -# endif +# endif _nss_files_init (cb); } +#endif /* Initialize the function pointers, following the double-checked locking idiom. */