diff options
| author | Paul Eggert <eggert@cs.ucla.edu> | 2024-12-17 14:02:41 -0800 |
|---|---|---|
| committer | Paul Eggert <eggert@cs.ucla.edu> | 2024-12-17 14:13:54 -0800 |
| commit | b1e5f6d6ef8432a9cce0664238de72d387730bd1 (patch) | |
| tree | 7eb50047793367bf8f2483e28fb716cfc4334c13 /lib | |
| parent | 22806c65f4f8d68547d33997d017039763b4bf6a (diff) | |
Update from Gnulib by running admin/merge-gnulib
* admin/merge-gnulib (AVOIDED_MODULES): Avoid gnulib-i18n.
* lib/stdlib.c, m4/selinux-selinux-h.m4:
New files, taken from Gnulib.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/acl-internal.c | 6 | ||||
| -rw-r--r-- | lib/acl.h | 59 | ||||
| -rw-r--r-- | lib/dirent.in.h | 95 | ||||
| -rw-r--r-- | lib/file-has-acl.c | 571 | ||||
| -rw-r--r-- | lib/getopt-cdefs.in.h | 10 | ||||
| -rw-r--r-- | lib/getopt-pfx-core.h | 7 | ||||
| -rw-r--r-- | lib/getopt.c | 4 | ||||
| -rw-r--r-- | lib/gettext.h | 32 | ||||
| -rw-r--r-- | lib/gnulib.mk.in | 50 | ||||
| -rw-r--r-- | lib/malloc.c | 11 | ||||
| -rw-r--r-- | lib/md5-stream.c | 3 | ||||
| -rw-r--r-- | lib/md5.h | 8 | ||||
| -rw-r--r-- | lib/memset_explicit.c | 5 | ||||
| -rw-r--r-- | lib/mini-gmp.c | 95 | ||||
| -rw-r--r-- | lib/mini-gmp.h | 1 | ||||
| -rw-r--r-- | lib/mktime-internal.h | 9 | ||||
| -rw-r--r-- | lib/mktime.c | 111 | ||||
| -rw-r--r-- | lib/nproc.c | 41 | ||||
| -rw-r--r-- | lib/pipe2.c | 2 | ||||
| -rw-r--r-- | lib/realloc.c | 71 | ||||
| -rw-r--r-- | lib/regex.h | 18 | ||||
| -rw-r--r-- | lib/regex_internal.c | 3 | ||||
| -rw-r--r-- | lib/regex_internal.h | 10 | ||||
| -rw-r--r-- | lib/stdio-impl.h | 2 | ||||
| -rw-r--r-- | lib/stdlib.c | 21 | ||||
| -rw-r--r-- | lib/stdlib.in.h | 43 | ||||
| -rw-r--r-- | lib/timegm.c | 3 | ||||
| -rw-r--r-- | lib/unistd.in.h | 5 | ||||
| -rw-r--r-- | lib/utimens.c | 68 | ||||
| -rw-r--r-- | lib/utimens.h | 10 |
30 files changed, 942 insertions, 432 deletions
diff --git a/lib/acl-internal.c b/lib/acl-internal.c index ae5398306af..b729126118a 100644 --- a/lib/acl-internal.c +++ b/lib/acl-internal.c @@ -19,10 +19,12 @@ #include <config.h> -#include "acl.h" - +/* Specification. */ +#define ACL_INTERNAL_INLINE _GL_EXTERN_INLINE #include "acl-internal.h" +#include "acl.h" + #if defined __CYGWIN__ # include <sys/types.h> # include <grp.h> diff --git a/lib/acl.h b/lib/acl.h index 475231c2db7..1d52345c668 100644 --- a/lib/acl.h +++ b/lib/acl.h @@ -32,9 +32,68 @@ extern "C" { #endif +/* file_has_acl flags guaranteed to not collide with any <dirent.h> + DT_* or _GL_DT_* value. */ +enum + { + /* Get scontext information as well. */ + ACL_GET_SCONTEXT = 0x10000, + + /* Follow symlinks. */ + ACL_SYMLINK_FOLLOW = 0x20000, + }; + +/* Information about an ACL. */ +struct aclinfo +{ + /* If 'size' is nonnegative, a buffer holding the concatenation + of extended attribute names, each terminated by NUL + (either u.__gl_acl_ch, or heap-allocated). */ + char *buf; + + /* The number of useful bytes at the start of buf, counting trailing NULs. + If negative, there was an error in getting the ACL info, + and u.err is the corresponding errno. */ + ssize_t size; + + /* Security context string. Do not modify its contents. */ + char *scontext; + /* Security context errno value. It is zero if there was no + error getting the security context. When nonzero, scontext is "?". */ + int scontext_err; + + union + { + /* An errno value, when there was an error getting the ACL info. */ + int err; + + /* A small array of char, big enough for most listxattr results. + The size is somewhat arbitrary; it equals the max length of a + trivial NFSv4 ACL (a size used by file-has-acl.c in 2023-2024 + but no longer relevant now), and a different value might be + better once experience is gained. For internal use only. */ + char __gl_acl_ch[152]; + } u; +}; bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST; int file_has_acl (char const *, struct stat const *); +int file_has_aclinfo (char const *restrict, struct aclinfo *restrict, int); + +#if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR +bool aclinfo_has_xattr (struct aclinfo const *, char const *) + _GL_ATTRIBUTE_PURE; +void aclinfo_free (struct aclinfo *); +#else +# define aclinfo_has_xattr(ai, xattr) false +# define aclinfo_free(ai) ((void) 0) +#endif +#if (HAVE_LINUX_XATTR_H && HAVE_LISTXATTR \ + && (HAVE_SMACK || USE_SELINUX_SELINUX_H)) +void aclinfo_scontext_free (char *); +#else +# define aclinfo_scontext_free(s) ((void) 0) +#endif int qset_acl (char const *, int, mode_t); int xset_acl (char const *, int, mode_t); diff --git a/lib/dirent.in.h b/lib/dirent.in.h index 7ba8fc64d89..a0ac39b4968 100644 --- a/lib/dirent.in.h +++ b/lib/dirent.in.h @@ -46,20 +46,95 @@ struct dirent char d_type; char d_name[1]; }; -/* Possible values for 'd_type'. */ -# define DT_UNKNOWN 0 -# define DT_FIFO 1 /* FIFO */ -# define DT_CHR 2 /* character device */ -# define DT_DIR 4 /* directory */ -# define DT_BLK 6 /* block device */ -# define DT_REG 8 /* regular file */ -# define DT_LNK 10 /* symbolic link */ -# define DT_SOCK 12 /* socket */ -# define DT_WHT 14 /* whiteout */ # define GNULIB_defined_struct_dirent 1 # endif #endif +/* 'd_type' macros specified in GNU, i.e., POSIX.1-2024 plus DT_WHT, + but not (yet) DT_MQ, DT_SEM, DT_SHM, DT_TMO. + These macros can be useful even on platforms that do not support + d_type or the corresponding file types. + The values of these macros are all in the 'unsigned char' range. + Default to the Linux values which are also popular elsewhere, + and check that all macros have distinct values. */ +#ifndef DT_UNKNOWN +# define DT_UNKNOWN 0 +#endif +#ifndef DT_FIFO +# define DT_FIFO 1 /* FIFO */ +#endif +#ifndef DT_CHR +# define DT_CHR 2 /* character device */ +#endif +#ifndef DT_DIR +# define DT_DIR 4 /* directory */ +#endif +#ifndef DT_BLK +# define DT_BLK 6 /* block device */ +#endif +#ifndef DT_REG +# define DT_REG 8 /* regular file */ +#endif +#ifndef DT_LNK +# define DT_LNK 10 /* symbolic link */ +#endif +#ifndef DT_SOCK +# define DT_SOCK 12 /* socket */ +#endif +#ifndef DT_WHT +# define DT_WHT 14 /* whiteout */ +#endif +static_assert (DT_UNKNOWN != DT_FIFO && DT_UNKNOWN != DT_CHR + && DT_UNKNOWN != DT_BLK && DT_UNKNOWN != DT_REG + && DT_UNKNOWN != DT_LNK && DT_UNKNOWN != DT_SOCK + && DT_UNKNOWN != DT_WHT + && DT_FIFO != DT_CHR && DT_FIFO != DT_BLK && DT_FIFO != DT_REG + && DT_FIFO != DT_LNK && DT_FIFO != DT_SOCK && DT_FIFO != DT_WHT + && DT_CHR != DT_BLK && DT_CHR != DT_REG && DT_CHR != DT_LNK + && DT_CHR != DT_SOCK && DT_CHR != DT_WHT + && DT_BLK != DT_REG && DT_BLK != DT_LNK && DT_BLK != DT_SOCK + && DT_BLK != DT_WHT + && DT_REG != DT_LNK && DT_REG != DT_SOCK && DT_REG != DT_WHT + && DT_LNK != DT_SOCK && DT_LNK != DT_WHT + && DT_SOCK != DT_WHT); + +/* Other optional information about a directory entry. */ +#define _GL_DT_NOTDIR 0x100 /* Not a directory */ + +/* Conversion between S_IF* and DT_* file types. */ +#if ! (defined IFTODT && defined DTTOIF) +# include <sys/stat.h> +# ifdef S_ISWHT +# define _GL_DIRENT_S_ISWHT(mode) S_ISWHT(mode) +# else +# define _GL_DIRENT_S_ISWHT(mode) 0 +# endif +# ifdef S_IFWHT +# define _GL_DIRENT_S_IFWHT S_IFWHT +# else +# define _GL_DIRENT_S_IFWHT (DT_WHT << 12) /* just a guess */ +# endif +#endif +/* Conversion from a 'stat' mode to a DT_* value. */ +#ifndef IFTODT +# define IFTODT(mode) \ + (S_ISREG (mode) ? DT_REG : S_ISDIR (mode) ? DT_DIR \ + : S_ISLNK (mode) ? DT_LNK : S_ISBLK (mode) ? DT_BLK \ + : S_ISCHR (mode) ? DT_CHR : S_ISFIFO (mode) ? DT_FIFO \ + : S_ISSOCK (mode) ? DT_SOCK \ + : _GL_DIRENT_S_ISWHT (mode) ? DT_WHT : DT_UNKNOWN) +#endif +/* Conversion from a DT_* value to a 'stat' mode. */ +#ifndef DTTOIF +# define DTTOIF(dirtype) \ + ((dirtype) == DT_REG ? S_IFREG : (dirtype) == DT_DIR ? S_IFDIR \ + : (dirtype) == DT_LNK ? S_IFLNK : (dirtype) == DT_BLK ? S_IFBLK \ + : (dirtype) == DT_CHR ? S_IFCHR : dirtype == DT_FIFO ? S_IFIFO \ + : (dirtype) == DT_SOCK ? S_IFSOCK \ + : (dirtype) == DT_WHT ? _GL_DIRENT_S_IFWHT \ + : (dirtype) << 12 /* just a guess */) +#endif + #if !@DIR_HAS_FD_MEMBER@ # if !GNULIB_defined_DIR /* struct gl_directory is a type with a field 'int fd_to_close'. diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 06759a4948c..7c29f201589 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -27,12 +27,30 @@ #include "acl.h" +#include <dirent.h> +#include <limits.h> + #include "acl-internal.h" #include "attribute.h" #include "minmax.h" -#if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR +/* Check the assumption that UCHAR_MAX < INT_MAX. */ +static_assert (ACL_SYMLINK_FOLLOW & ~ (unsigned char) -1); + +static char const UNKNOWN_SECURITY_CONTEXT[] = "?"; + +#if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR +# define USE_LINUX_XATTR true +#else +# define USE_LINUX_XATTR false +#endif + +#if USE_LINUX_XATTR +# if USE_SELINUX_SELINUX_H +# include <selinux/selinux.h> +# endif # include <stdckdint.h> +# include <stdint.h> # include <string.h> # include <arpa/inet.h> # include <sys/xattr.h> @@ -47,26 +65,186 @@ # define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default" # endif +# ifdef HAVE_SMACK +# include <sys/smack.h> +# else +static char const * +smack_smackfs_path (void) +{ + return NULL; +} +static ssize_t +smack_new_label_from_path (MAYBE_UNUSED const char *path, + MAYBE_UNUSED const char *xattr, + MAYBE_UNUSED int follow, MAYBE_UNUSED char **label) +{ + return -1; +} +# endif +static bool +is_smack_enabled (void) +{ + return !!smack_smackfs_path (); +} + enum { /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */ ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001, ACE4_IDENTIFIER_GROUP = 0x00000040 }; -/* Return true if ATTR is in the set represented by the NUL-terminated - strings in LISTBUF, which is of size LISTSIZE. */ +/* Does AI's xattr set contain XATTR? */ -ATTRIBUTE_PURE static bool -have_xattr (char const *attr, char const *listbuf, ssize_t listsize) +bool +aclinfo_has_xattr (struct aclinfo const *ai, char const *xattr) { - char const *blim = listbuf + listsize; - for (char const *b = listbuf; b < blim; b += strlen (b) + 1) - for (char const *a = attr; *a == *b; a++, b++) - if (!*a) - return true; + if (0 < ai->size) + { + char const *blim = ai->buf + ai->size; + for (char const *b = ai->buf; b < blim; b += strlen (b) + 1) + for (char const *a = xattr; *a == *b; a++, b++) + if (!*a) + return true; + } return false; } +/* Get attributes of the file NAME into AI, if USE_ACL. + If FLAGS & ACL_GET_SCONTEXT, also get security context. + If FLAGS & ACL_SYMLINK_FOLLOW, follow symbolic links. */ +static void +get_aclinfo (char const *name, struct aclinfo *ai, int flags) +{ + int scontext_err = ENOTSUP; + ai->buf = ai->u.__gl_acl_ch; + ssize_t acl_alloc = sizeof ai->u.__gl_acl_ch; + + if (! (USE_ACL || flags & ACL_GET_SCONTEXT)) + ai->size = 0; + else + { + ssize_t (*lsxattr) (char const *, char *, size_t) + = (flags & ACL_SYMLINK_FOLLOW ? listxattr : llistxattr); + while (true) + { + ai->size = lsxattr (name, ai->buf, acl_alloc); + if (0 < ai->size) + break; + ai->u.err = ai->size < 0 ? errno : 0; + if (! (ai->size < 0 && ai->u.err == ERANGE && acl_alloc < SSIZE_MAX)) + break; + + /* The buffer was too small. Find how large it should have been. */ + ssize_t size = lsxattr (name, NULL, 0); + if (size <= 0) + { + ai->size = size; + ai->u.err = size < 0 ? errno : 0; + break; + } + + /* Grow allocation to at least 'size'. Grow it by a nontrivial + amount, to defend against denial of service by an adversary + that fiddles with ACLs. */ + if (ai->buf != ai->u.__gl_acl_ch) + { + free (ai->buf); + ai->buf = ai->u.__gl_acl_ch; + } + if (ckd_add (&acl_alloc, acl_alloc, acl_alloc >> 1)) + acl_alloc = SSIZE_MAX; + if (acl_alloc < size) + acl_alloc = size; + if (SIZE_MAX < acl_alloc) + { + ai->u.err = ENOMEM; + break; + } + char *newbuf = malloc (acl_alloc); + if (!newbuf) + { + ai->u.err = errno; + break; + } + ai->buf = newbuf; + } + } + + if (0 < ai->size && flags & ACL_GET_SCONTEXT) + { + if (is_smack_enabled ()) + { + if (aclinfo_has_xattr (ai, XATTR_NAME_SMACK)) + { + ssize_t r = smack_new_label_from_path (name, "security.SMACK64", + flags & ACL_SYMLINK_FOLLOW, + &ai->scontext); + scontext_err = r < 0 ? errno : 0; + } + } + else + { +# if USE_SELINUX_SELINUX_H + if (aclinfo_has_xattr (ai, XATTR_NAME_SELINUX)) + { + ssize_t r = + ((flags & ACL_SYMLINK_FOLLOW ? getfilecon : lgetfilecon) + (name, &ai->scontext)); + scontext_err = r < 0 ? errno : 0; +# ifndef SE_SELINUX_INLINE + /* Gnulib's selinux-h module is not in use, so getfilecon and + lgetfilecon can misbehave, be it via an old version of + libselinux where these would return 0 and set the result + context to NULL, or via a modern kernel+lib operating on a + file from a disk whose attributes were set by a kernel from + around 2006. In that latter case, the functions return a + length of 10 for the "unlabeled" context. Map both failures + to a return value of -1, and set errno to ENOTSUP in the + first case, and ENODATA in the latter. */ + if (r == 0) + scontext_err = ENOTSUP; + if (r == 10 && memcmp (ai->scontext, "unlabeled", 10) == 0) + { + freecon (ai->scontext); + scontext_err = ENODATA; + } +# endif + } +# endif + } + } + ai->scontext_err = scontext_err; + if (scontext_err) + ai->scontext = (char *) UNKNOWN_SECURITY_CONTEXT; +} + +# ifndef aclinfo_scontext_free +/* Free the pointer that file_has_aclinfo put into scontext. + However, do nothing if the argument is a null pointer; + This lets the caller replace the scontext member with a null pointer if it + is willing to own the member and call this function later. */ +void +aclinfo_scontext_free (char *scontext) +{ + if (scontext != UNKNOWN_SECURITY_CONTEXT) + { + if (is_smack_enabled ()) + free (scontext); + else if (scontext) + freecon (scontext); + } +} +# endif + +/* Free AI's heap storage. */ +void +aclinfo_free (struct aclinfo *ai) +{ + if (ai->buf != ai->u.__gl_acl_ch) + free (ai->buf); + aclinfo_scontext_free (ai->scontext); +} + /* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial. -1 upon failure to determine it. Possibly change errno. Assume that the ACL is valid, except avoid undefined behavior even if invalid. @@ -150,196 +328,183 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes) 0 if ACLs are not supported, or if NAME has no or only a base ACL, and -1 (setting errno) on error. Note callers can determine if ACLs are not supported as errno is set in that case also. - SB must be set to the stat buffer of NAME, - obtained through stat() or lstat(). */ - + Set *AI to ACL info regardless of return value. + FLAGS should be a <dirent.h> d_type value, optionally ORed with + - _GL_DT_NOTDIR if it is known that NAME is not a directory, + - ACL_GET_SCONTEXT to retrieve security context and return 1 if present, + - ACL_SYMLINK_FOLLOW to follow the link if NAME is a symbolic link; + otherwise do not follow them if possible. + If the d_type value is not known, use DT_UNKNOWN though this may be less + efficient. */ int -file_has_acl (char const *name, struct stat const *sb) +file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + struct aclinfo *restrict ai, int flags) { -#if USE_ACL - if (! S_ISLNK (sb->st_mode)) - { + MAYBE_UNUSED unsigned char d_type = flags & UCHAR_MAX; -# if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR - int initial_errno = errno; +#if USE_LINUX_XATTR + int initial_errno = errno; + get_aclinfo (name, ai, flags); - /* The max length of a trivial NFSv4 ACL is 6 words for owner, - 6 for group, 7 for everyone, all times 2 because there are - both allow and deny ACEs. There are 6 words for owner - because of type, flag, mask, wholen, "OWNER@"+pad and - similarly for group; everyone is another word to hold - "EVERYONE@". */ - typedef uint32_t trivial_NFSv4_xattr_buf[2 * (6 + 6 + 7)]; + if (ai->size <= 0) + { + errno = ai->size < 0 ? ai->u.err : initial_errno; + return ai->size; + } - /* A buffer large enough to hold any trivial NFSv4 ACL, - and also useful as a small array of char. */ - union { - trivial_NFSv4_xattr_buf xattr; - char ch[sizeof (trivial_NFSv4_xattr_buf)]; - } stackbuf; + /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs, + but if it has an NFSv4 ACL that's the one that matters. + In earlier Fedora the two types of ACLs were mutually exclusive. + Attempt to work correctly on both kinds of systems. */ - char *listbuf = stackbuf.ch; - ssize_t listbufsize = sizeof stackbuf.ch; - char *heapbuf = NULL; - ssize_t listsize; + if (!aclinfo_has_xattr (ai, XATTR_NAME_NFSV4_ACL)) + return + (aclinfo_has_xattr (ai, XATTR_NAME_POSIX_ACL_ACCESS) + || ((d_type == DT_DIR || d_type == DT_UNKNOWN) + && aclinfo_has_xattr (ai, XATTR_NAME_POSIX_ACL_DEFAULT))); - /* Use listxattr first, as this means just one syscall in the - typical case where the file lacks an ACL. Try stackbuf - first, falling back on malloc if stackbuf is too small. */ - while ((listsize = listxattr (name, listbuf, listbufsize)) < 0 - && errno == ERANGE) - { - free (heapbuf); - ssize_t newsize = listxattr (name, NULL, 0); - if (newsize <= 0) - return newsize; + /* A buffer large enough to hold any trivial NFSv4 ACL. + The max length of a trivial NFSv4 ACL is 6 words for owner, + 6 for group, 7 for everyone, all times 2 because there are both + allow and deny ACEs. There are 6 words for owner because of + type, flag, mask, wholen, "OWNER@"+pad and similarly for group; + everyone is another word to hold "EVERYONE@". */ + uint32_t buf[2 * (6 + 6 + 7)]; - /* Grow LISTBUFSIZE to at least NEWSIZE. Grow it by a - nontrivial amount too, to defend against denial of - service by an adversary that fiddles with ACLs. */ - bool overflow = ckd_add (&listbufsize, listbufsize, listbufsize >> 1); - listbufsize = MAX (listbufsize, newsize); - if (overflow || SIZE_MAX < listbufsize) - { - errno = ENOMEM; - return -1; - } + int ret = ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr) + (name, XATTR_NAME_NFSV4_ACL, buf, sizeof buf)); + if (ret < 0) + switch (errno) + { + case ENODATA: return 0; + case ERANGE : return 1; /* ACL must be nontrivial. */ + default: return - acl_errno_valid (errno); + } - listbuf = heapbuf = malloc (listbufsize); - if (!listbuf) - return -1; - } + /* It looks like a trivial ACL, but investigate further. */ + ret = acl_nfs4_nontrivial (buf, ret); + errno = ret < 0 ? EINVAL : initial_errno; + return ret; - /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs, - but if it has an NFSv4 ACL that's the one that matters. - In earlier Fedora the two types of ACLs were mutually exclusive. - Attempt to work correctly on both kinds of systems. */ - bool nfsv4_acl - = 0 < listsize && have_xattr (XATTR_NAME_NFSV4_ACL, listbuf, listsize); - int ret - = (listsize <= 0 ? listsize - : (nfsv4_acl - || have_xattr (XATTR_NAME_POSIX_ACL_ACCESS, listbuf, listsize) - || (S_ISDIR (sb->st_mode) - && have_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, - listbuf, listsize)))); - free (heapbuf); +#else /* !USE_LINUX_XATTR */ - /* If there is an NFSv4 ACL, follow up with a getxattr syscall - to see whether the NFSv4 ACL is nontrivial. */ - if (nfsv4_acl) - { - ret = getxattr (name, XATTR_NAME_NFSV4_ACL, - stackbuf.xattr, sizeof stackbuf.xattr); - if (ret < 0) - switch (errno) - { - case ENODATA: return 0; - case ERANGE : return 1; /* ACL must be nontrivial. */ - } - else - { - /* It looks like a trivial ACL, but investigate further. */ - ret = acl_nfs4_nontrivial (stackbuf.xattr, ret); - if (ret < 0) - { - errno = EINVAL; - return ret; - } - errno = initial_errno; - } - } - if (ret < 0) - return - acl_errno_valid (errno); - return ret; + ai->buf = ai->u.__gl_acl_ch; + ai->size = -1; + ai->u.err = ENOTSUP; + ai->scontext = (char *) UNKNOWN_SECURITY_CONTEXT; + ai->scontext_err = ENOTSUP; -# elif HAVE_ACL_GET_FILE +# if USE_ACL +# if HAVE_ACL_GET_FILE - /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ - /* Linux, FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */ - int ret; + { + /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ + /* Linux, FreeBSD, NetBSD >= 10, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */ + int ret; - if (HAVE_ACL_EXTENDED_FILE) /* Linux */ - { - /* On Linux, acl_extended_file is an optimized function: It only - makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for - ACL_TYPE_DEFAULT. */ - ret = acl_extended_file (name); - } - else /* FreeBSD, Mac OS X, IRIX, Tru64, Cygwin >= 2.5 */ - { -# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ - /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) - and acl_get_file (name, ACL_TYPE_DEFAULT) - always return NULL / EINVAL. There is no point in making - these two useless calls. The real ACL is retrieved through - acl_get_file (name, ACL_TYPE_EXTENDED). */ - acl_t acl = acl_get_file (name, ACL_TYPE_EXTENDED); - if (acl) - { - ret = acl_extended_nontrivial (acl); - acl_free (acl); - } - else - ret = -1; -# else /* FreeBSD, IRIX, Tru64, Cygwin >= 2.5 */ - acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); - if (acl) - { - int saved_errno; +# if HAVE_ACL_EXTENDED_FILE /* Linux */ + /* On Linux, acl_extended_file is an optimized function: It only + makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for + ACL_TYPE_DEFAULT. */ + ret = ((flags & ACL_SYMLINK_FOLLOW + ? acl_extended_file + : acl_extended_file_nofollow) + (name)); +# elif HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ + /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) + and acl_get_file (name, ACL_TYPE_DEFAULT) + always return NULL / EINVAL. There is no point in making + these two useless calls. The real ACL is retrieved through + acl_get_file (name, ACL_TYPE_EXTENDED). */ + acl_t acl = ((flags & ACL_SYMLINK_FOLLOW + ? acl_get_file + : acl_get_link_np) + (name, ACL_TYPE_EXTENDED)); + if (acl) + { + ret = acl_extended_nontrivial (acl); + acl_free (acl); + } + else + ret = -1; +# else /* FreeBSD, NetBSD >= 10, IRIX, Tru64, Cygwin >= 2.5 */ + acl_t (*acl_get_file_or_link) (char const *, acl_type_t) = acl_get_file; +# if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10 */ + if (! (flags & ACL_SYMLINK_FOLLOW)) + acl_get_file_or_link = acl_get_link_np; +# endif - ret = acl_access_nontrivial (acl); - saved_errno = errno; - acl_free (acl); - errno = saved_errno; -# if HAVE_ACL_FREE_TEXT /* Tru64 */ - /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always - returns NULL with errno not set. There is no point in - making this call. */ -# else /* FreeBSD, IRIX, Cygwin >= 2.5 */ - /* On Linux, FreeBSD, IRIX, acl_get_file (name, ACL_TYPE_ACCESS) - and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory - either both succeed or both fail; it depends on the - file system. Therefore there is no point in making the second - call if the first one already failed. */ - if (ret == 0 && S_ISDIR (sb->st_mode)) - { - acl = acl_get_file (name, ACL_TYPE_DEFAULT); - if (acl) - { -# ifdef __CYGWIN__ /* Cygwin >= 2.5 */ - ret = acl_access_nontrivial (acl); - saved_errno = errno; - acl_free (acl); - errno = saved_errno; -# else - ret = (0 < acl_entries (acl)); - acl_free (acl); + acl_t acl = acl_get_file_or_link (name, ACL_TYPE_ACCESS); + if (acl) + { + ret = acl_access_nontrivial (acl); + int saved_errno = errno; + acl_free (acl); + errno = saved_errno; +# if HAVE_ACL_FREE_TEXT /* Tru64 */ + /* On OSF/1, acl_get_file (name, ACL_TYPE_DEFAULT) always + returns NULL with errno not set. There is no point in + making this call. */ +# else /* FreeBSD, NetBSD >= 10, IRIX, Cygwin >= 2.5 */ + /* On Linux, FreeBSD, NetBSD, IRIX, + acl_get_file (name, ACL_TYPE_ACCESS) + and acl_get_file (name, ACL_TYPE_DEFAULT) on a directory + either both succeed or both fail; it depends on the + file system. Therefore there is no point in making the second + call if the first one already failed. */ + if (ret == 0 + && (d_type == DT_DIR + || (d_type == DT_UNKNOWN && !(flags & _GL_DT_NOTDIR)))) + { + acl = acl_get_file_or_link (name, ACL_TYPE_DEFAULT); + if (acl) + { +# ifdef __CYGWIN__ /* Cygwin >= 2.5 */ + ret = acl_access_nontrivial (acl); + saved_errno = errno; + acl_free (acl); + errno = saved_errno; +# else + ret = (0 < acl_entries (acl)); + acl_free (acl); +# endif + } + else + { + ret = -1; +# ifdef __CYGWIN__ /* Cygwin >= 2.5 */ + if (d_type == DT_UNKNOWN) + ret = 0; +# endif + } + } # endif - } - else - ret = -1; - } + } + else + ret = -1; # endif - } - else - ret = -1; -# endif - } - if (ret < 0) - return - acl_errno_valid (errno); - return ret; -# elif HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */ + return ret < 0 ? - acl_errno_valid (errno) : ret; + } + +# else /* !HAVE_ACL_GET_FILE */ -# if defined ACL_NO_TRIVIAL + /* The remaining APIs always follow symlinks and operate on + platforms where symlinks do not have ACLs, so skip the APIs if + NAME is known to be a symlink. */ + if (d_type != DT_LNK) + { + +# if HAVE_FACL && defined GETACL /* Solaris, Cygwin < 2.5, not HP-UX */ + +# ifdef ACL_NO_TRIVIAL /* Solaris 10 (newer version), which has additional API declared in <sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial, acl_fromtext, ...). */ return acl_trivial (name); -# else /* Solaris, Cygwin, general case */ +# else /* Solaris, Cygwin, general case */ /* Solaris 2.5 through Solaris 10, Cygwin, and contemporaneous versions of Unixware. The acl() call returns the access and default ACL both @@ -374,10 +539,7 @@ file_has_acl (char const *name, struct stat const *sb) entries = malloced = (aclent_t *) malloc (alloc * sizeof (aclent_t)); if (entries == NULL) - { - errno = ENOMEM; - return -1; - } + return -1; continue; } break; @@ -415,7 +577,7 @@ file_has_acl (char const *name, struct stat const *sb) free (malloced); } -# ifdef ACE_GETACL +# ifdef ACE_GETACL /* Solaris also has a different variant of ACLs, used in ZFS and NFSv4 file systems (whereas the other ones are used in UFS file systems). */ { @@ -447,10 +609,7 @@ file_has_acl (char const *name, struct stat const *sb) alloc = 2 * alloc; /* <= alloc_max */ entries = malloced = (ace_t *) malloc (alloc * sizeof (ace_t)); if (entries == NULL) - { - errno = ENOMEM; - return -1; - } + return -1; continue; } break; @@ -491,12 +650,12 @@ file_has_acl (char const *name, struct stat const *sb) } free (malloced); } -# endif +# endif return 0; -# endif +# endif -# elif HAVE_GETACL /* HP-UX */ +# elif HAVE_GETACL /* HP-UX */ { struct acl_entry entries[NACLENTRIES]; @@ -539,7 +698,7 @@ file_has_acl (char const *name, struct stat const *sb) } } -# if HAVE_ACLV_H /* HP-UX >= 11.11 */ +# if HAVE_ACLV_H /* HP-UX >= 11.11 */ { struct acl entries[NACLVENTRIES]; @@ -574,9 +733,9 @@ file_has_acl (char const *name, struct stat const *sb) } } -# endif +# endif -# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ +# elif HAVE_ACLX_GET && defined ACL_AIX_WIP /* AIX */ acl_type_t type; char aclbuf[1024]; @@ -604,10 +763,7 @@ file_has_acl (char const *name, struct stat const *sb) free (acl); acl = malloc (aclsize); if (acl == NULL) - { - errno = ENOMEM; - return -1; - } + return -1; } if (type.u64 == ACL_AIXC) @@ -634,7 +790,7 @@ file_has_acl (char const *name, struct stat const *sb) return -1; } -# elif HAVE_STATACL /* older AIX */ +# elif HAVE_STATACL /* older AIX */ union { struct acl a; char room[4096]; } u; @@ -643,7 +799,7 @@ file_has_acl (char const *name, struct stat const *sb) return acl_nontrivial (&u.a); -# elif HAVE_ACLSORT /* NonStop Kernel */ +# elif HAVE_ACLSORT /* NonStop Kernel */ { struct acl entries[NACLENTRIES]; @@ -675,10 +831,29 @@ file_has_acl (char const *name, struct stat const *sb) return acl_nontrivial (count, entries); } } - -# endif +# endif } +# endif +# endif #endif return 0; } + +/* Return 1 if NAME has a nontrivial access control list, + 0 if ACLs are not supported, or if NAME has no or only a base ACL, + and -1 (setting errno) on error. Note callers can determine + if ACLs are not supported as errno is set in that case also. + SB must be set to the stat buffer of NAME, + obtained through stat() or lstat(). */ +int +file_has_acl (char const *name, struct stat const *sb) +{ + int flags = IFTODT (sb->st_mode); + if (!S_ISDIR (sb->st_mode)) + flags |= _GL_DT_NOTDIR; + struct aclinfo ai; + int r = file_has_aclinfo (name, &ai, flags); + aclinfo_free (&ai); + return r; +} diff --git a/lib/getopt-cdefs.in.h b/lib/getopt-cdefs.in.h index a1d304d49e8..9d704a9f6e5 100644 --- a/lib/getopt-cdefs.in.h +++ b/lib/getopt-cdefs.in.h @@ -46,10 +46,14 @@ # endif #endif +#if defined __clang__ + /* clang really only groks GNU C 4.2, regardless of its value of __GNUC__. */ +# undef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) ((maj) < 4 + ((min) <= 2)) +#endif #ifndef __GNUC_PREREQ -# if defined __GNUC__ && defined __GNUC_VERSION__ -# define __GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__)) # else # define __GNUC_PREREQ(maj, min) 0 # endif diff --git a/lib/getopt-pfx-core.h b/lib/getopt-pfx-core.h index 78b7816aa42..df2cb183a52 100644 --- a/lib/getopt-pfx-core.h +++ b/lib/getopt-pfx-core.h @@ -31,6 +31,13 @@ functions and variables. Renaming avoids problems with some compilers and linkers. */ #ifdef __GETOPT_PREFIX + +/* Include platform-dependent header files that may declare getopt() and + friends. */ +# if defined _AIX || defined __hpux || defined __sun || defined __QNX__ +# include <stdio.h> +# endif + # ifndef __GETOPT_ID # define __GETOPT_CONCAT(x, y) x ## y # define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y) diff --git a/lib/getopt.c b/lib/getopt.c index ea2d1a529c4..47800c1b35b 100644 --- a/lib/getopt.c +++ b/lib/getopt.c @@ -42,7 +42,7 @@ # define funlockfile(fp) _IO_funlockfile (fp) #else # include "gettext.h" -# define _(msgid) gettext (msgid) +# define _(msgid) dgettext ("gnulib", msgid) /* When used standalone, flockfile and funlockfile might not be available. */ # if (!defined _POSIX_THREAD_SAFE_FUNCTIONS \ @@ -732,7 +732,7 @@ _getopt_internal (int argc, char **argv, const char *optstring, NAME (int argc, char *const *argv, const char *optstring) \ { \ return _getopt_internal (argc, (char **)argv, optstring, \ - 0, 0, 0, POSIXLY_CORRECT); \ + NULL, NULL, 0, POSIXLY_CORRECT); \ } #ifdef _LIBC diff --git a/lib/gettext.h b/lib/gettext.h index 39d5ae4daa5..bf0aa41e230 100644 --- a/lib/gettext.h +++ b/lib/gettext.h @@ -1,6 +1,5 @@ /* Convenience header for conditional use of GNU <libintl.h>. - Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2024 Free Software - Foundation, Inc. + Copyright (C) 1995-2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -18,6 +17,7 @@ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 + /* NLS can be disabled through the configure --disable-nls option or through "#define ENABLE NLS 0" before including this file. */ #if defined ENABLE_NLS && ENABLE_NLS @@ -45,19 +45,19 @@ as well because people using "gettext.h" will not include <libintl.h>, and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> is OK. */ -#if defined(__sun) -# include <locale.h> -#endif +# if defined(__sun) +# include <locale.h> +# endif /* Many header files from the libstdc++ coming with g++ 3.3 or newer include <libintl.h>, which chokes if dcgettext is defined as a macro. So include it now, to make later inclusions of <libintl.h> a NOP. */ -#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) -# include <cstdlib> -# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H -# include <libintl.h> +# if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) +# include <cstdlib> +# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H +# include <libintl.h> +# endif # endif -#endif /* Disabled NLS. The casts to 'const char *' serve the purpose of producing warnings @@ -93,12 +93,14 @@ #endif + /* Prefer gnulib's setlocale override over libintl's setlocale override. */ #ifdef GNULIB_defined_setlocale # undef setlocale # define setlocale rpl_setlocale #endif + /* A pseudo function call that serves as a marker for the automated extraction of messages, but does not call gettext(). The run-time translation is done at a different place in the code. @@ -108,6 +110,7 @@ initializer for static 'char[]' or 'const char[]' variables. */ #define gettext_noop(String) String + /* The separator between msgctxt and msgid in a .mo file. */ #define GETTEXT_CONTEXT_GLUE "\004" @@ -115,6 +118,9 @@ MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be short and rarely need to change. The letter 'p' stands for 'particular' or 'special'. */ + +#include <locale.h> /* for LC_MESSAGES */ + #ifdef DEFAULT_TEXT_DOMAIN # define pgettext(Msgctxt, Msgid) \ pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) @@ -178,11 +184,12 @@ npgettext_aux (const char *domain, return translation; } + /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID can be arbitrary expressions. But for string literals these macros are less efficient than those above. */ -#include <string.h> +#include <string.h> /* for memcpy */ /* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported. This relates to the -Wvla and -Wvla-larger-than warnings, enabled in @@ -199,7 +206,7 @@ npgettext_aux (const char *domain, #endif #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS -#include <stdlib.h> +# include <stdlib.h> /* for malloc, free */ #endif #define pgettext_expr(Msgctxt, Msgid) \ @@ -297,4 +304,5 @@ dcnpgettext_expr (const char *domain, return (n == 1 ? msgid : msgid_plural); } + #endif /* _LIBGETTEXT_H */ diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 5e541d9af1f..53275a4e62f 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -42,6 +42,7 @@ # --avoid=dup \ # --avoid=fchdir \ # --avoid=fstat \ +# --avoid=gnulib-i18n \ # --avoid=iswblank \ # --avoid=iswctype \ # --avoid=iswdigit \ @@ -80,6 +81,7 @@ # alloca-opt \ # binary-io \ # boot-time \ +# builtin-expect \ # byteswap \ # c-ctype \ # c-strcase \ @@ -261,7 +263,6 @@ DYNLIB_OBJ = @DYNLIB_OBJ@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ -EGREP = @EGREP@ EMACSRES = @EMACSRES@ EMACS_MANIFEST = @EMACS_MANIFEST@ EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@ @@ -336,6 +337,7 @@ GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION = @GL_COND_OBJ_PTHREAD_SIGMASK_CONDITION@ GL_COND_OBJ_RAWMEMCHR_CONDITION = @GL_COND_OBJ_RAWMEMCHR_CONDITION@ GL_COND_OBJ_READLINKAT_CONDITION = @GL_COND_OBJ_READLINKAT_CONDITION@ GL_COND_OBJ_READLINK_CONDITION = @GL_COND_OBJ_READLINK_CONDITION@ +GL_COND_OBJ_REALLOC_POSIX_CONDITION = @GL_COND_OBJ_REALLOC_POSIX_CONDITION@ GL_COND_OBJ_REGEX_CONDITION = @GL_COND_OBJ_REGEX_CONDITION@ GL_COND_OBJ_SIG2STR_CONDITION = @GL_COND_OBJ_SIG2STR_CONDITION@ GL_COND_OBJ_SIGDESCR_NP_CONDITION = @GL_COND_OBJ_SIGDESCR_NP_CONDITION@ @@ -584,7 +586,6 @@ GL_GNULIB_READDIR = @GL_GNULIB_READDIR@ GL_GNULIB_READLINK = @GL_GNULIB_READLINK@ GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@ GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@ -GL_GNULIB_REALLOC_GNU = @GL_GNULIB_REALLOC_GNU@ GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@ GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@ GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@ @@ -707,7 +708,6 @@ GNUSTEP_CFLAGS = @GNUSTEP_CFLAGS@ GNU_OBJC_CFLAGS = @GNU_OBJC_CFLAGS@ GOBJECT_CFLAGS = @GOBJECT_CFLAGS@ GOBJECT_LIBS = @GOBJECT_LIBS@ -GREP = @GREP@ GSETTINGS_CFLAGS = @GSETTINGS_CFLAGS@ GSETTINGS_LIBS = @GSETTINGS_LIBS@ GTK_CFLAGS = @GTK_CFLAGS@ @@ -1031,6 +1031,7 @@ LIB_MATH = @LIB_MATH@ LIB_NANOSLEEP = @LIB_NANOSLEEP@ LIB_PTHREAD = @LIB_PTHREAD@ LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ +LIB_SELINUX = @LIB_SELINUX@ LIB_TIMER_TIME = @LIB_TIMER_TIME@ LIB_WSOCK32 = @LIB_WSOCK32@ LIB_XATTR = @LIB_XATTR@ @@ -1277,7 +1278,6 @@ REPLACE_READDIR = @REPLACE_READDIR@ REPLACE_READLINK = @REPLACE_READLINK@ REPLACE_READLINKAT = @REPLACE_READLINKAT@ REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@ -REPLACE_REALLOC_FOR_REALLOC_GNU = @REPLACE_REALLOC_FOR_REALLOC_GNU@ REPLACE_REALLOC_FOR_REALLOC_POSIX = @REPLACE_REALLOC_FOR_REALLOC_POSIX@ REPLACE_REALPATH = @REPLACE_REALPATH@ REPLACE_REMOVE = @REPLACE_REMOVE@ @@ -1384,6 +1384,7 @@ UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@ UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@ UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@ USE_ACL = @USE_ACL@ +USE_SELINUX_SELINUX_H = @USE_SELINUX_SELINUX_H@ USE_STARTUP_NOTIFICATION = @USE_STARTUP_NOTIFICATION@ VMLIMIT_OBJ = @VMLIMIT_OBJ@ W32_LIBS = @W32_LIBS@ @@ -1470,16 +1471,13 @@ gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b_CONDITION = @gl_GNULIB_ENABLE gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31_CONDITION = @gl_GNULIB_ENABLED_5264294aa0a5557541b53c8c741f7f31_CONDITION@ gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c_CONDITION = @gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c_CONDITION@ gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4_CONDITION = @gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4_CONDITION@ -gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec_CONDITION = @gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec_CONDITION@ gl_GNULIB_ENABLED_8444034ea779b88768865bb60b4fb8c9_CONDITION = @gl_GNULIB_ENABLED_8444034ea779b88768865bb60b4fb8c9_CONDITION@ gl_GNULIB_ENABLED_925677f0343de64b89a9f0c790b4104c_CONDITION = @gl_GNULIB_ENABLED_925677f0343de64b89a9f0c790b4104c_CONDITION@ gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1_CONDITION = @gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1_CONDITION@ gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36_CONDITION = @gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36_CONDITION@ gl_GNULIB_ENABLED_cloexec_CONDITION = @gl_GNULIB_ENABLED_cloexec_CONDITION@ -gl_GNULIB_ENABLED_d3b2383720ee0e541357aa2aac598e2b_CONDITION = @gl_GNULIB_ENABLED_d3b2383720ee0e541357aa2aac598e2b_CONDITION@ gl_GNULIB_ENABLED_dirfd_CONDITION = @gl_GNULIB_ENABLED_dirfd_CONDITION@ gl_GNULIB_ENABLED_e80bf6f757095d2e5fc94dafb8f8fc8b_CONDITION = @gl_GNULIB_ENABLED_e80bf6f757095d2e5fc94dafb8f8fc8b_CONDITION@ -gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION = @gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION@ gl_GNULIB_ENABLED_endian_CONDITION = @gl_GNULIB_ENABLED_endian_CONDITION@ gl_GNULIB_ENABLED_euidaccess_CONDITION = @gl_GNULIB_ENABLED_euidaccess_CONDITION@ gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION = @gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION@ @@ -2694,9 +2692,7 @@ endif ## begin gnulib module malloc-posix ifeq (,$(OMIT_GNULIB_MODULE_malloc-posix)) -ifneq (,$(gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION)) -endif EXTRA_DIST += malloc.c EXTRA_libgnu_a_SOURCES += malloc.c @@ -2925,30 +2921,16 @@ EXTRA_libgnu_a_SOURCES += at-func.c endif ## end gnulib module readlinkat -## begin gnulib module realloc-gnu -ifeq (,$(OMIT_GNULIB_MODULE_realloc-gnu)) - -ifneq (,$(gl_GNULIB_ENABLED_d3b2383720ee0e541357aa2aac598e2b_CONDITION)) - -endif -EXTRA_DIST += realloc.c - -EXTRA_libgnu_a_SOURCES += realloc.c - -endif -## end gnulib module realloc-gnu - ## begin gnulib module realloc-posix ifeq (,$(OMIT_GNULIB_MODULE_realloc-posix)) ifneq (,$(gl_GNULIB_ENABLED_61bcaca76b3e6f9ae55d57a1c3193bc4_CONDITION)) - +ifneq (,$(GL_COND_OBJ_REALLOC_POSIX_CONDITION)) +libgnu_a_SOURCES += realloc.c endif -EXTRA_DIST += realloc.c - -EXTRA_libgnu_a_SOURCES += realloc.c endif +endif ## end gnulib module realloc-posix ## begin gnulib module regex @@ -3459,9 +3441,8 @@ endif ifeq (,$(OMIT_GNULIB_MODULE_stdlib)) BUILT_SOURCES += stdlib.h +libgnu_a_SOURCES += stdlib.c -# We need the following in order to create <stdlib.h> when the system -# doesn't have one that works with the given compiler. stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ $(_NORETURN_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H) $(gl_V_at)$(SED_HEADER_STDOUT) \ @@ -3500,7 +3481,6 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's/@''GNULIB_RAND''@/$(GL_GNULIB_RAND)/g' \ -e 's/@''GNULIB_RANDOM''@/$(GL_GNULIB_RANDOM)/g' \ -e 's/@''GNULIB_RANDOM_R''@/$(GL_GNULIB_RANDOM_R)/g' \ - -e 's/@''GNULIB_REALLOC_GNU''@/$(GL_GNULIB_REALLOC_GNU)/g' \ -e 's/@''GNULIB_REALLOC_POSIX''@/$(GL_GNULIB_REALLOC_POSIX)/g' \ -e 's/@''GNULIB_REALLOCARRAY''@/$(GL_GNULIB_REALLOCARRAY)/g' \ -e 's/@''GNULIB_REALPATH''@/$(GL_GNULIB_REALPATH)/g' \ @@ -3602,7 +3582,6 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's|@''REPLACE_RAND''@|$(REPLACE_RAND)|g' \ -e 's|@''REPLACE_RANDOM''@|$(REPLACE_RANDOM)|g' \ -e 's|@''REPLACE_RANDOM_R''@|$(REPLACE_RANDOM_R)|g' \ - -e 's|@''REPLACE_REALLOC_FOR_REALLOC_GNU''@|$(REPLACE_REALLOC_FOR_REALLOC_GNU)|g' \ -e 's|@''REPLACE_REALLOC_FOR_REALLOC_POSIX''@|$(REPLACE_REALLOC_FOR_REALLOC_POSIX)|g' \ -e 's|@''REPLACE_REALLOCARRAY''@|$(REPLACE_REALLOCARRAY)|g' \ -e 's|@''REPLACE_REALPATH''@|$(REPLACE_REALPATH)|g' \ @@ -4446,17 +4425,6 @@ EXTRA_DIST += vla.h endif ## end gnulib module vla -## begin gnulib module xalloc-oversized -ifeq (,$(OMIT_GNULIB_MODULE_xalloc-oversized)) - -ifneq (,$(gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec_CONDITION)) - -endif -EXTRA_DIST += xalloc-oversized.h - -endif -## end gnulib module xalloc-oversized - mostlyclean-local: mostlyclean-generic @for dir in '' $(MOSTLYCLEANDIRS); do \ diff --git a/lib/malloc.c b/lib/malloc.c index 2a7867a1d1f..045ff82c1a7 100644 --- a/lib/malloc.c +++ b/lib/malloc.c @@ -17,28 +17,33 @@ /* written by Jim Meyering and Bruno Haible */ +/* Ensure that we call the system's malloc() below. */ #define _GL_USE_STDLIB_ALLOC 1 #include <config.h> #include <stdlib.h> #include <errno.h> - -#include "xalloc-oversized.h" +#include <stdckdint.h> /* Allocate an N-byte block of memory from the heap, even if N is 0. */ void * rpl_malloc (size_t n) { +#if !HAVE_MALLOC_0_NONNULL if (n == 0) n = 1; +#endif - if (xalloc_oversized (n, 1)) +#if !HAVE_MALLOC_PTRDIFF + ptrdiff_t signed_n; + if (ckd_add (&signed_n, n, 0)) { errno = ENOMEM; return NULL; } +#endif void *result = malloc (n); diff --git a/lib/md5-stream.c b/lib/md5-stream.c index fdd2bd8b4bf..2cbdda6b0fa 100644 --- a/lib/md5-stream.c +++ b/lib/md5-stream.c @@ -22,9 +22,6 @@ #include <config.h> /* Specification. */ -#if HAVE_OPENSSL_MD5 -# define GL_OPENSSL_INLINE _GL_EXTERN_INLINE -#endif #include "md5.h" #include <stdlib.h> diff --git a/lib/md5.h b/lib/md5.h index 2f470703f5c..94cc6994cc1 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -52,10 +52,14 @@ #define MD5_DIGEST_SIZE 16 #define MD5_BLOCK_SIZE 64 +#if defined __clang__ + /* clang really only groks GNU C 4.2, regardless of its value of __GNUC__. */ +# undef __GNUC_PREREQ +# define __GNUC_PREREQ(maj, min) ((maj) < 4 + ((min) <= 2)) +#endif #ifndef __GNUC_PREREQ # if defined __GNUC__ && defined __GNUC_MINOR__ -# define __GNUC_PREREQ(maj, min) \ - ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# define __GNUC_PREREQ(maj, min) ((maj) < __GNUC__ + ((min) <= __GNUC_MINOR__)) # else # define __GNUC_PREREQ(maj, min) 0 # endif diff --git a/lib/memset_explicit.c b/lib/memset_explicit.c index 33c09873482..a5d2b00b7ea 100644 --- a/lib/memset_explicit.c +++ b/lib/memset_explicit.c @@ -27,7 +27,10 @@ memset_explicit (void *s, int c, size_t len) #if HAVE_EXPLICIT_MEMSET return explicit_memset (s, c, len); #elif HAVE_MEMSET_S - (void) memset_s (s, len, c, len); +# if !HAVE_MEMSET_S_SUPPORTS_ZERO + if (len > 0) +# endif + (void) memset_s (s, len, c, len); return s; #elif defined __GNUC__ && !defined __clang__ memset (s, c, len); diff --git a/lib/mini-gmp.c b/lib/mini-gmp.c index c580a8fc025..c97dc7e6cfa 100644 --- a/lib/mini-gmp.c +++ b/lib/mini-gmp.c @@ -2706,6 +2706,66 @@ mpn_gcd_11 (mp_limb_t u, mp_limb_t v) return u << shift; } +mp_size_t +mpn_gcd (mp_ptr rp, mp_ptr up, mp_size_t un, mp_ptr vp, mp_size_t vn) +{ + assert (un >= vn); + assert (vn > 0); + assert (!GMP_MPN_OVERLAP_P (up, un, vp, vn)); + assert (vp[vn-1] > 0); + assert ((up[0] | vp[0]) & 1); + + if (un > vn) + mpn_div_qr (NULL, up, un, vp, vn); + + un = mpn_normalized_size (up, vn); + if (un == 0) + { + mpn_copyi (rp, vp, vn); + return vn; + } + + if (!(vp[0] & 1)) + MPN_PTR_SWAP (up, un, vp, vn); + + while (un > 1 || vn > 1) + { + int shift; + assert (vp[0] & 1); + + while (up[0] == 0) + { + up++; + un--; + } + gmp_ctz (shift, up[0]); + if (shift > 0) + { + gmp_assert_nocarry (mpn_rshift(up, up, un, shift)); + un -= (up[un-1] == 0); + } + + if (un < vn) + MPN_PTR_SWAP (up, un, vp, vn); + else if (un == vn) + { + int c = mpn_cmp (up, vp, un); + if (c == 0) + { + mpn_copyi (rp, up, un); + return un; + } + else if (c < 0) + MP_PTR_SWAP (up, vp); + } + + gmp_assert_nocarry (mpn_sub (up, up, un, vp, vn)); + un = mpn_normalized_size (up, un); + } + rp[0] = mpn_gcd_11 (up[0], vp[0]); + return 1; +} + unsigned long mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v) { @@ -2765,42 +2825,11 @@ mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v) if (tu->_mp_size < tv->_mp_size) mpz_swap (tu, tv); - mpz_tdiv_r (tu, tu, tv); - if (tu->_mp_size == 0) - { - mpz_swap (g, tv); - } - else - for (;;) - { - int c; - - mpz_make_odd (tu); - c = mpz_cmp (tu, tv); - if (c == 0) - { - mpz_swap (g, tu); - break; - } - if (c < 0) - mpz_swap (tu, tv); + tu->_mp_size = mpn_gcd (tu->_mp_d, tu->_mp_d, tu->_mp_size, tv->_mp_d, tv->_mp_size); + mpz_mul_2exp (g, tu, gz); - if (tv->_mp_size == 1) - { - mp_limb_t *gp; - - mpz_tdiv_r (tu, tu, tv); - gp = MPZ_REALLOC (g, 1); /* gp = mpz_limbs_modify (g, 1); */ - *gp = mpn_gcd_11 (tu->_mp_d[0], tv->_mp_d[0]); - - g->_mp_size = *gp != 0; /* mpz_limbs_finish (g, 1); */ - break; - } - mpz_sub (tu, tu, tv); - } mpz_clear (tu); mpz_clear (tv); - mpz_mul_2exp (g, g, gz); } void diff --git a/lib/mini-gmp.h b/lib/mini-gmp.h index 59c24cf5111..f28cb360ce1 100644 --- a/lib/mini-gmp.h +++ b/lib/mini-gmp.h @@ -105,6 +105,7 @@ void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t); void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t); int mpn_perfect_square_p (mp_srcptr, mp_size_t); mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t); +mp_size_t mpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t); mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int); diff --git a/lib/mktime-internal.h b/lib/mktime-internal.h index 0693aaf1402..3e2848c1210 100644 --- a/lib/mktime-internal.h +++ b/lib/mktime-internal.h @@ -71,9 +71,8 @@ typedef int mktime_offset_t; #endif /* Subroutine of mktime. Return the time_t representation of TP and - normalize TP, given that a struct tm * maps to a time_t as performed - by FUNC. Record next guess for localtime-gmtime offset in *OFFSET. */ -extern __time64_t __mktime_internal (struct tm *tp, - struct tm *(*func) (__time64_t const *, - struct tm *), + normalize TP, given that a struct tm * maps to a time_t. If + LOCAL, the mapping is performed by localtime_r, otherwise by gmtime_r. + Record next guess for localtime-gmtime offset in *OFFSET. */ +extern __time64_t __mktime_internal (struct tm *tp, bool local, mktime_offset_t *offset) attribute_hidden; diff --git a/lib/mktime.c b/lib/mktime.c index c704f415740..81d58fd01a3 100644 --- a/lib/mktime.c +++ b/lib/mktime.c @@ -51,7 +51,6 @@ #include <string.h> #include <intprops.h> -#include <verify.h> #ifndef NEED_MKTIME_INTERNAL # define NEED_MKTIME_INTERNAL 0 @@ -119,12 +118,12 @@ my_tzset (void) __time64_t values that mktime can generate even on platforms where __time64_t is wider than the int components of struct tm. */ -#if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60 +# if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60 typedef long int long_int; -#else +# else typedef long long int long_int; -#endif -verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60); +# endif +static_assert (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60); /* Shift A right by B bits portably, by dividing A by 2**B and truncating towards minus infinity. B should be in the range 0 <= B @@ -155,9 +154,9 @@ static long_int const mktime_max = (TYPE_MAXIMUM (long_int) < TYPE_MAXIMUM (__time64_t) ? TYPE_MAXIMUM (long_int) : TYPE_MAXIMUM (__time64_t)); -#define EPOCH_YEAR 1970 -#define TM_YEAR_BASE 1900 -verify (TM_YEAR_BASE % 100 == 0); +# define EPOCH_YEAR 1970 +# define TM_YEAR_BASE 1900 +static_assert (TM_YEAR_BASE % 100 == 0); /* Is YEAR + TM_YEAR_BASE a leap year? */ static bool @@ -172,9 +171,9 @@ leapyear (long_int year) } /* How many days come before each month (0-12). */ -#ifndef _LIBC +# ifndef _LIBC static -#endif +# endif const unsigned short int __mon_yday[2][13] = { /* Normal years. */ @@ -206,7 +205,7 @@ static long_int ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1, int year0, int yday0, int hour0, int min0, int sec0) { - verify (-1 / 2 == 0); + static_assert (-1 / 2 == 0); /* Compute intervening leap days correctly even if year is negative. Take care to avoid integer overflow here. */ @@ -251,29 +250,33 @@ tm_diff (long_int year, long_int yday, int hour, int min, int sec, tp->tm_hour, tp->tm_min, tp->tm_sec); } -/* Use CONVERT to convert T to a struct tm value in *TM. T must be in - range for __time64_t. Return TM if successful, NULL (setting errno) on - failure. */ +/* Convert T to a struct tm value in *TM. Use localtime64_r if LOCAL, + otherwise gmtime64_r. T must be in range for __time64_t. Return + TM if successful, NULL (setting errno) on failure. */ static struct tm * -convert_time (struct tm *(*convert) (const __time64_t *, struct tm *), - long_int t, struct tm *tm) +convert_time (long_int t, bool local, struct tm *tm) { __time64_t x = t; - return convert (&x, tm); + if (local) + return __localtime64_r (&x, tm); + else + return __gmtime64_r (&x, tm); } +/* Call it __tzconvert to sync with other parts of glibc. */ +#define __tz_convert convert_time -/* Use CONVERT to convert *T to a broken down time in *TP. - If *T is out of range for conversion, adjust it so that - it is the nearest in-range value and then convert that. - A value is in range if it fits in both __time64_t and long_int. - Return TP on success, NULL (setting errno) on failure. */ +/* Convert *T to a broken down time in *TP (as if by localtime if + LOCAL, otherwise as if by gmtime). If *T is out of range for + conversion, adjust it so that it is the nearest in-range value and + then convert that. A value is in range if it fits in both + __time64_t and long_int. Return TP on success, NULL (setting + errno) on failure. */ static struct tm * -ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *), - long_int *t, struct tm *tp) +ranged_convert (bool local, long_int *t, struct tm *tp) { long_int t1 = (*t < mktime_min ? mktime_min : *t <= mktime_max ? *t : mktime_max); - struct tm *r = convert_time (convert, t1, tp); + struct tm *r = __tz_convert (t1, local, tp); if (r) { *t = t1; @@ -294,7 +297,7 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *), long_int mid = long_int_avg (ok, bad); if (mid == ok || mid == bad) break; - if (convert_time (convert, mid, tp)) + if (__tz_convert (mid, local, tp)) ok = mid, oktm = *tp; else if (errno != EOVERFLOW) return NULL; @@ -310,36 +313,45 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *), } -/* Convert *TP to a __time64_t value, inverting - the monotonic and mostly-unit-linear conversion function CONVERT. - Use *OFFSET to keep track of a guess at the offset of the result, +/* Convert *TP to a __time64_t value. If LOCAL, the reverse mapping + is performed as if localtime, otherwise as if by gmtime. Use + *OFFSET to keep track of a guess at the offset of the result, compared to what the result would be for UTC without leap seconds. - If *OFFSET's guess is correct, only one CONVERT call is needed. - If successful, set *TP to the canonicalized struct tm; + If *OFFSET's guess is correct, only one reverse mapping call is + needed. If successful, set *TP to the canonicalized struct tm; otherwise leave *TP alone, return ((time_t) -1) and set errno. This function is external because it is used also by timegm.c. */ __time64_t -__mktime_internal (struct tm *tp, - struct tm *(*convert) (const __time64_t *, struct tm *), - mktime_offset_t *offset) +__mktime_internal (struct tm *tp, bool local, mktime_offset_t *offset) { struct tm tm; - /* The maximum number of probes (calls to CONVERT) should be enough - to handle any combinations of time zone rule changes, solar time, - leap seconds, and oscillations around a spring-forward gap. - POSIX.1 prohibits leap seconds, but some hosts have them anyway. */ + /* The maximum number of probes should be enough to handle any + combinations of time zone rule changes, solar time, leap seconds, + and oscillations around a spring-forward gap. POSIX.1 prohibits + leap seconds, but some hosts have them anyway. */ int remaining_probes = 6; - /* Time requested. Copy it in case CONVERT modifies *TP; this can - occur if TP is localtime's returned value and CONVERT is localtime. */ +#ifndef _LIBC + /* Gnulib mktime doesn't lock the tz state, so it may need to probe + more often if some other thread changes local time while + __mktime_internal is probing. Double the number of probes; this + should suffice for practical cases that are at all likely. */ + remaining_probes *= 2; +#endif + + /* Time requested. Copy it in case gmtime/localtime modify *TP; + this can occur if TP is localtime's returned value and CONVERT is + localtime. */ int sec = tp->tm_sec; int min = tp->tm_min; int hour = tp->tm_hour; int mday = tp->tm_mday; int mon = tp->tm_mon; int year_requested = tp->tm_year; - int isdst = tp->tm_isdst; + + /* Ignore any tm_isdst request for timegm. */ + int isdst = local ? tp->tm_isdst : 0; /* 1 if the previous probe was DST. */ int dst2 = 0; @@ -390,7 +402,7 @@ __mktime_internal (struct tm *tp, while (true) { - if (! ranged_convert (convert, &t, &tm)) + if (! ranged_convert (local, &t, &tm)) return -1; long_int dt = tm_diff (year, yday, hour, min, sec, &tm); if (dt == 0) @@ -469,7 +481,7 @@ __mktime_internal (struct tm *tp, if (! ckd_add (&ot, t, delta * direction)) { struct tm otm; - if (! ranged_convert (convert, &ot, &otm)) + if (! ranged_convert (local, &ot, &otm)) return -1; if (! isdst_differ (isdst, otm.tm_isdst)) { @@ -479,7 +491,7 @@ __mktime_internal (struct tm *tp, &otm); if (mktime_min <= gt && gt <= mktime_max) { - if (convert_time (convert, gt, &tm)) + if (__tz_convert (gt, local, &tm)) { t = gt; goto offset_found; @@ -493,7 +505,7 @@ __mktime_internal (struct tm *tp, /* No unusual DST offset was found nearby. Assume one-hour DST. */ t += 60 * 60 * dst_difference; - if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm)) + if (mktime_min <= t && t <= mktime_max && __tz_convert (t, local, &tm)) goto offset_found; __set_errno (EOVERFLOW); @@ -520,7 +532,7 @@ __mktime_internal (struct tm *tp, __set_errno (EOVERFLOW); return -1; } - if (! convert_time (convert, t, &tm)) + if (! __tz_convert (t, local, &tm)) return -1; } @@ -536,14 +548,13 @@ __mktime_internal (struct tm *tp, __time64_t __mktime64 (struct tm *tp) { - /* POSIX.1 8.1.1 requires that whenever mktime() is called, the - time zone names contained in the external variable 'tzname' shall - be set as if the tzset() function had been called. */ + /* POSIX.1 requires mktime to set external variables like 'tzname' + as though tzset had been called. */ __tzset (); # if defined _LIBC || NEED_MKTIME_WORKING static mktime_offset_t localtime_offset; - return __mktime_internal (tp, __localtime64_r, &localtime_offset); + return __mktime_internal (tp, true, &localtime_offset); # else # undef mktime return mktime (tp); diff --git a/lib/nproc.c b/lib/nproc.c index 92a07e82890..0b5898d88ff 100644 --- a/lib/nproc.c +++ b/lib/nproc.c @@ -20,6 +20,7 @@ #include <config.h> #include "nproc.h" +#include <errno.h> #include <limits.h> #include <stdlib.h> #include <unistd.h> @@ -125,6 +126,46 @@ num_processors_via_affinity_mask (void) } } #elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ + /* There are two ways to use the sched_getaffinity() function: + - With a statically-sized cpu_set_t. + - With a dynamically-sized cpu_set_t. + Documentation: + <https://www.kernel.org/doc/man-pages/online/pages/man2/sched_getaffinity.2.html> + <https://www.kernel.org/doc/man-pages/online/pages/man3/CPU_SET.3.html> + The second way has the advantage that it works on systems with more than + 1024 CPUs. The first way has the advantage that it works also when memory + is tight. */ +# if defined CPU_ALLOC_SIZE /* glibc >= 2.6 */ + { + unsigned int alloc_count = 1024; + for (;;) + { + cpu_set_t *set = CPU_ALLOC (alloc_count); + if (set == NULL) + /* Out of memory. */ + break; + unsigned int size = CPU_ALLOC_SIZE (alloc_count); + if (sched_getaffinity (0, size, set) == 0) + { + unsigned int count = CPU_COUNT_S (size, set); + CPU_FREE (set); + return count; + } + if (errno != EINVAL) + { + /* Some other error. */ + CPU_FREE (set); + return 0; + } + CPU_FREE (set); + /* Retry with some larger cpu_set_t. */ + alloc_count *= 2; + if (alloc_count == 0) + /* Integer overflow. Avoid an endless loop. */ + return 0; + } + } +# endif { cpu_set_t set; diff --git a/lib/pipe2.c b/lib/pipe2.c index 7b476df3457..e290f94a94a 100644 --- a/lib/pipe2.c +++ b/lib/pipe2.c @@ -40,7 +40,7 @@ pipe2 (int fd[2], int flags) { /* Mingw _pipe() corrupts fd on failure; also, if we succeed at creating the pipe but later fail at changing fcntl, we want - to leave fd unchanged: http://austingroupbugs.net/view.php?id=467 */ + to leave fd unchanged: https://austingroupbugs.net/view.php?id=467 */ int tmp[2]; tmp[0] = fd[0]; tmp[1] = fd[1]; diff --git a/lib/realloc.c b/lib/realloc.c index 0573139625e..58044745f45 100644 --- a/lib/realloc.c +++ b/lib/realloc.c @@ -18,17 +18,21 @@ /* written by Jim Meyering and Bruno Haible */ +/* Ensure that we call the system's realloc() below. */ +#define _GL_USE_STDLIB_ALLOC 1 #include <config.h> +#define _GL_REALLOC_INLINE _GL_EXTERN_INLINE #include <stdlib.h> #include <errno.h> +#include <stdckdint.h> -#include "xalloc-oversized.h" +#ifdef __CHERI_PURE_CAPABILITY__ +# include <cheri.h> +#endif -/* Call the system's realloc below. This file does not define - _GL_USE_STDLIB_ALLOC because it needs Gnulib's malloc if present. */ -#undef realloc +#ifndef _GL_INLINE_RPL_REALLOC /* Change the size of an allocated block of memory P to N bytes, with error checking. If P is NULL, use malloc. Otherwise if N is zero, @@ -37,27 +41,70 @@ void * rpl_realloc (void *p, size_t n) { - if (p == NULL) - return malloc (n); + size_t n1 = n; if (n == 0) { - free (p); - return NULL; +# if NEED_SANITIZED_REALLOC + /* When P is non-null, ISO C23 ยง7.24.3.7.(3) says realloc (P, 0) has + undefined behavior even though C17 and earlier partially defined + the behavior. Let the programmer know. + When the undefined-behaviour sanitizers report this case, i.e. when + <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117233> and + <https://github.com/llvm/llvm-project/issues/113065> + have been closed and new releases of GCC and clang have been made, + we can revisit this code. */ + if (p != NULL) + abort (); +# endif + + /* realloc (NULL, 0) acts like glibc malloc (0), i.e., like malloc (1) + except the caller cannot dereference any non-null return. + + realloc (P, 0) with non-null P is a messier situation. + As mentioned above, C23 says behavior is undefined. + POSIX.1-2024 extends C17 to say realloc (P, 0) + either fails by setting errno and returning a null pointer, + or succeeds by freeing P and then either: + (a) setting errno=EINVAL and returning a null pointer; or + (b) acting like a successful malloc (0). + glibc 1 through 2.1 realloc acted like (b), + which conforms to C17, to C23 and to POSIX.1-2024. + glibc 2.1.1+ realloc acts like (a) except it does not set errno; + this conforms to C17 and to C23 but not to POSIX.1-2024. + Quite possibly future versions of POSIX will change, + due either to C23 or to (a)'s semantics being messy. + Act like (b), as that's easy, matches GNU, BSD and V7 malloc, + matches BSD and V7 realloc, and requires no extra code at + caller sites. */ + +# if !HAVE_REALLOC_0_NONNULL + n1 = 1; +# endif } - if (xalloc_oversized (n, 1)) +# if !HAVE_MALLOC_PTRDIFF + ptrdiff_t signed_n; + if (ckd_add (&signed_n, n, 0)) { errno = ENOMEM; return NULL; } +# endif - void *result = realloc (p, n); + void *result = realloc (p, n1); -#if !HAVE_MALLOC_POSIX +# if !HAVE_MALLOC_POSIX if (result == NULL) errno = ENOMEM; -#endif +# endif + +# ifdef __CHERI_PURE_CAPABILITY__ + if (result != NULL) + result = cheri_bounds_set (result, n); +# endif return result; } + +#endif diff --git a/lib/regex.h b/lib/regex.h index ccf40cebc0e..004dc624050 100644 --- a/lib/regex.h +++ b/lib/regex.h @@ -647,10 +647,12 @@ extern int re_exec (const char *); || 2 < __GNUC__ + (95 <= __GNUC_MINOR__) \ || __clang_major__ >= 3 # define _Restrict_ __restrict -# elif 199901L <= __STDC_VERSION__ || defined restrict -# define _Restrict_ restrict # else -# define _Restrict_ +# if 199901L <= __STDC_VERSION__ || defined restrict +# define _Restrict_ restrict +# else +# define _Restrict_ +# endif # endif #endif /* For the ISO C99 syntax @@ -661,13 +663,15 @@ extern int re_exec (const char *); #ifndef _Restrict_arr_ # ifdef __restrict_arr # define _Restrict_arr_ __restrict_arr -# elif ((199901L <= __STDC_VERSION__ \ +# else +# if ((199901L <= __STDC_VERSION__ \ || 3 < __GNUC__ + (1 <= __GNUC_MINOR__) \ || __clang_major__ >= 3) \ && !defined __cplusplus) -# define _Restrict_arr_ _Restrict_ -# else -# define _Restrict_arr_ +# define _Restrict_arr_ _Restrict_ +# else +# define _Restrict_arr_ +# endif # endif #endif diff --git a/lib/regex_internal.c b/lib/regex_internal.c index 8cd096ebcfb..6ccf701f266 100644 --- a/lib/regex_internal.c +++ b/lib/regex_internal.c @@ -937,8 +937,7 @@ re_node_set_alloc (re_node_set *set, Idx size) set->alloc = size; set->nelem = 0; set->elems = re_malloc (Idx, size); - if (__glibc_unlikely (set->elems == NULL) - && (MALLOC_0_IS_NONNULL || size != 0)) + if (__glibc_unlikely (set->elems == NULL)) return REG_ESPACE; return REG_NOERROR; } diff --git a/lib/regex_internal.h b/lib/regex_internal.h index 6165cb17c70..02c2ca68960 100644 --- a/lib/regex_internal.h +++ b/lib/regex_internal.h @@ -100,10 +100,12 @@ /* This is for other GNU distributions with internationalized messages. */ #if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC # include <libintl.h> +# undef gettext # ifdef _LIBC -# undef gettext # define gettext(msgid) \ __dcgettext (_libc_intl_domainname, msgid, LC_MESSAGES) +# else +# define gettext(msgid) dgettext ("gnulib", msgid) # endif #else # undef gettext @@ -436,12 +438,6 @@ typedef struct re_dfa_t re_dfa_t; #define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) #define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) -#ifdef _LIBC -# define MALLOC_0_IS_NONNULL 1 -#elif !defined MALLOC_0_IS_NONNULL -# define MALLOC_0_IS_NONNULL 0 -#endif - #ifndef MAX # define MAX(a,b) ((a) < (b) ? (b) : (a)) #endif diff --git a/lib/stdio-impl.h b/lib/stdio-impl.h index 63ebf7c64b7..dfb5166171a 100644 --- a/lib/stdio-impl.h +++ b/lib/stdio-impl.h @@ -110,7 +110,7 @@ # endif # if (defined __NetBSD__ && __NetBSD_Version__ >= 105270000) || defined __OpenBSD__ || defined __minix /* NetBSD >= 1.5ZA, OpenBSD, Minix 3 */ - /* See <http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup> + /* See <https://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup> and <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup> and <https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/master/lib/libc/stdio/fileext.h> */ struct __sfileext diff --git a/lib/stdlib.c b/lib/stdlib.c new file mode 100644 index 00000000000..521d64627dc --- /dev/null +++ b/lib/stdlib.c @@ -0,0 +1,21 @@ +/* Inline functions for <stdlib.h>. + + Copyright (C) 2024 Free Software Foundation, Inc. + + This file 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. + + This file 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 this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#define _GL_STDLIB_INLINE _GL_EXTERN_INLINE +#include <stdlib.h> diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index 6667f426ad9..adbef69131b 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -54,7 +54,7 @@ /* This file uses _Noreturn, _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOTHROW, _GL_ATTRIBUTE_PURE, - GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */ + _GL_INLINE_HEADER_BEGIN, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */ #if !_GL_CONFIG_H_INCLUDED #error "Please include config.h first." #endif @@ -130,6 +130,14 @@ struct random_data # include <string> #endif +_GL_INLINE_HEADER_BEGIN +#ifndef _GL_STDLIB_INLINE +# define _GL_STDLIB_INLINE _GL_INLINE +#endif +#ifndef _GL_REALLOC_INLINE +# define _GL_REALLOC_INLINE _GL_INLINE +#endif + /* _GL_ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers that can be freed by passing them as the Ith argument to the function F. */ @@ -283,8 +291,8 @@ _GL_CXXALIASWARN (free); #elif defined GNULIB_POSIXCHECK # undef free /* Assume free is always declared. */ -_GL_WARN_ON_USE (free, "free is not future POSIX compliant everywhere - " - "use gnulib module free for portability"); +_GL_WARN_ON_USE (free, "free is not POSIX:2024 compliant everywhere - " + "use gnulib module free-posix for portability"); #endif @@ -367,9 +375,10 @@ _GL_WARN_ON_USE (atoll, "atoll is unportable - " #endif #if @GNULIB_CALLOC_POSIX@ -# if (@GNULIB_CALLOC_POSIX@ && @REPLACE_CALLOC_FOR_CALLOC_POSIX@) \ +# if @REPLACE_CALLOC_FOR_CALLOC_POSIX@ \ || (@GNULIB_CALLOC_GNU@ && @REPLACE_CALLOC_FOR_CALLOC_GNU@) -# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# if !((defined __cplusplus && defined GNULIB_NAMESPACE) \ + || _GL_USE_STDLIB_ALLOC) # undef calloc # define calloc rpl_calloc # endif @@ -681,7 +690,7 @@ _GL_WARN_ON_USE (grantpt, "grantpt is not portable - " by never specifying a zero size), so it does not need malloc or realloc to be redefined. */ #if @GNULIB_MALLOC_POSIX@ -# if (@GNULIB_MALLOC_POSIX@ && @REPLACE_MALLOC_FOR_MALLOC_POSIX@) \ +# if @REPLACE_MALLOC_FOR_MALLOC_POSIX@ \ || (@GNULIB_MALLOC_GNU@ && @REPLACE_MALLOC_FOR_MALLOC_GNU@) # if !((defined __cplusplus && defined GNULIB_NAMESPACE) \ || _GL_USE_STDLIB_ALLOC) @@ -740,11 +749,12 @@ _GL_WARN_ON_USE (malloc, "malloc is not POSIX compliant everywhere - " /* Return maximum number of bytes of a multibyte character. */ #if @REPLACE_MB_CUR_MAX@ # if !GNULIB_defined_MB_CUR_MAX -static inline -int gl_MB_CUR_MAX (void) +_GL_STDLIB_INLINE int +gl_MB_CUR_MAX (void) { /* Turn the value 3 to the value 4, as needed for the UTF-8 encoding. */ - return MB_CUR_MAX + (MB_CUR_MAX == 3); + int gl_mb_cur_max = MB_CUR_MAX; + return gl_mb_cur_max == 3 ? 4 : gl_mb_cur_max; } # undef MB_CUR_MAX # define MB_CUR_MAX gl_MB_CUR_MAX () @@ -1454,16 +1464,25 @@ _GL_WARN_ON_USE (setstate_r, "setstate_r is unportable - " #if @GNULIB_REALLOC_POSIX@ -# if (@GNULIB_REALLOC_POSIX@ && @REPLACE_REALLOC_FOR_REALLOC_POSIX@) \ - || (@GNULIB_REALLOC_GNU@ && @REPLACE_REALLOC_FOR_REALLOC_GNU@) +# if @REPLACE_REALLOC_FOR_REALLOC_POSIX@ +# if @REPLACE_REALLOC_FOR_REALLOC_POSIX@ == 2 +# define _GL_INLINE_RPL_REALLOC 1 +_GL_REALLOC_INLINE void * +rpl_realloc (void *ptr, size_t size) +{ + return realloc (ptr, size ? size : 1); +} +# endif # if !((defined __cplusplus && defined GNULIB_NAMESPACE) \ || _GL_USE_STDLIB_ALLOC) # undef realloc # define realloc rpl_realloc # endif +# if !defined _GL_INLINE_RPL_REALLOC _GL_FUNCDECL_RPL (realloc, void *, (void *ptr, size_t size), _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_NODISCARD); +# endif _GL_CXXALIAS_RPL (realloc, void *, (void *ptr, size_t size)); # else # if __GNUC__ >= 11 && !defined __clang__ @@ -1968,6 +1987,8 @@ _GL_CXXALIASWARN (wctomb); #endif +_GL_INLINE_HEADER_END + #endif /* _@GUARD_PREFIX@_STDLIB_H */ #endif /* _@GUARD_PREFIX@_STDLIB_H */ #endif diff --git a/lib/timegm.c b/lib/timegm.c index e5cf30c0198..ba28b3ecd96 100644 --- a/lib/timegm.c +++ b/lib/timegm.c @@ -30,8 +30,7 @@ __time64_t __timegm64 (struct tm *tmp) { static mktime_offset_t gmtime_offset; - tmp->tm_isdst = 0; - return __mktime_internal (tmp, __gmtime64_r, &gmtime_offset); + return __mktime_internal (tmp, false, &gmtime_offset); } #if defined _LIBC && __TIMESIZE != 64 diff --git a/lib/unistd.in.h b/lib/unistd.in.h index 20b1356fd38..ceb3cb48f15 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -181,6 +181,9 @@ _GL_INLINE_HEADER_BEGIN #ifndef _GL_UNISTD_INLINE # define _GL_UNISTD_INLINE _GL_INLINE #endif +#ifndef _GL_GETPAGESIZE_INLINE +# define _GL_GETPAGESIZE_INLINE _GL_INLINE +#endif /* Hide some function declarations from <winsock2.h>. */ @@ -1478,7 +1481,7 @@ _GL_FUNCDECL_SYS (getpagesize, int, (void), ); # define getpagesize() _gl_getpagesize () # else # if !GNULIB_defined_getpagesize_function -_GL_UNISTD_INLINE int +_GL_GETPAGESIZE_INLINE int getpagesize () { return _gl_getpagesize (); diff --git a/lib/utimens.c b/lib/utimens.c index cd86a44ea76..3c81b5c3492 100644 --- a/lib/utimens.c +++ b/lib/utimens.c @@ -78,6 +78,21 @@ static int utimensat_works_really; static int lutimensat_works_really; #endif /* HAVE_UTIMENSAT || HAVE_FUTIMENS */ +static bool +is_valid_timespec (struct timespec const *timespec) +{ + return (timespec->tv_nsec == UTIME_NOW + || timespec->tv_nsec == UTIME_OMIT + || (0 <= timespec->tv_nsec && timespec->tv_nsec < TIMESPEC_HZ)); +} + +static bool +is_valid_timespecs (struct timespec const timespec[2]) +{ + return (is_valid_timespec (×pec[0]) + && is_valid_timespec (×pec[1])); +} + /* Validate the requested timestamps. Return 0 if the resulting timespec can be used for utimensat (after possibly modifying it to work around bugs in utimensat). Return a positive value if the @@ -90,14 +105,7 @@ validate_timespec (struct timespec timespec[2]) { int result = 0; int utime_omit_count = 0; - if ((timespec[0].tv_nsec != UTIME_NOW - && timespec[0].tv_nsec != UTIME_OMIT - && ! (0 <= timespec[0].tv_nsec - && timespec[0].tv_nsec < TIMESPEC_HZ)) - || (timespec[1].tv_nsec != UTIME_NOW - && timespec[1].tv_nsec != UTIME_OMIT - && ! (0 <= timespec[1].tv_nsec - && timespec[1].tv_nsec < TIMESPEC_HZ))) + if (!is_valid_timespecs (timespec)) { errno = EINVAL; return -1; @@ -516,24 +524,44 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2]) } } -#if !HAVE_UTIMENS /* Set the access and modification timestamps of FILE to be TIMESPEC[0] and TIMESPEC[1], respectively. */ int utimens (char const *file, struct timespec const timespec[2]) +#undef utimens { +#if HAVE_UTIMENS + /* NetBSD's native utimens() does not fulfil the Gnulib expectations: + At least in NetBSD 10.0, it does not validate the timespec argument. */ + if (timespec != NULL && !is_valid_timespecs (timespec)) + { + errno = EINVAL; + return -1; + } + return utimens (file, timespec); +#else return fdutimens (-1, file, timespec); -} #endif +} -#if !HAVE_LUTIMENS /* Set the access and modification timestamps of FILE to be TIMESPEC[0] and TIMESPEC[1], respectively, without dereferencing symlinks. Fail with ENOSYS if the platform does not support changing symlink timestamps, but FILE was a symlink. */ int lutimens (char const *file, struct timespec const timespec[2]) +#undef lutimens { +#if HAVE_LUTIMENS + /* NetBSD's native lutimens() does not fulfil the Gnulib expectations: + At least in NetBSD 10.0, it does not validate the timespec argument. */ + if (timespec != NULL && !is_valid_timespecs (timespec)) + { + errno = EINVAL; + return -1; + } + return lutimens (file, timespec); +#else struct timespec adjusted_timespec[2]; struct timespec *ts = timespec ? adjusted_timespec : NULL; int adjustment_needed = 0; @@ -553,11 +581,11 @@ lutimens (char const *file, struct timespec const timespec[2]) fdutimens' worry about buggy NFS clients. But we do have to worry about bogus return values. */ -#if HAVE_UTIMENSAT +# if HAVE_UTIMENSAT if (0 <= lutimensat_works_really) { int result; -# if defined __linux__ || defined __sun || defined __NetBSD__ +# if defined __linux__ || defined __sun || defined __NetBSD__ /* As recently as Linux kernel 2.6.32 (Dec 2009), several file systems (xfs, ntfs-3g) have bugs with a single UTIME_OMIT, but work if both times are either explicitly specified or @@ -582,9 +610,9 @@ lutimens (char const *file, struct timespec const timespec[2]) /* Note that st is good, in case utimensat gives ENOSYS. */ adjustment_needed++; } -# endif +# endif result = utimensat (AT_FDCWD, file, ts, AT_SYMLINK_NOFOLLOW); -# ifdef __linux__ +# ifdef __linux__ /* Work around a kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=442352 https://bugzilla.redhat.com/show_bug.cgi?id=449910 @@ -594,7 +622,7 @@ lutimens (char const *file, struct timespec const timespec[2]) are no longer in common use. */ if (0 < result) errno = ENOSYS; -# endif +# endif if (result == 0 || errno != ENOSYS) { utimensat_works_really = 1; @@ -603,7 +631,7 @@ lutimens (char const *file, struct timespec const timespec[2]) } } lutimensat_works_really = -1; -#endif /* HAVE_UTIMENSAT */ +# endif /* HAVE_UTIMENSAT */ /* The platform lacks an interface to set file timestamps with nanosecond resolution, so do the best we can, discarding any @@ -619,7 +647,7 @@ lutimens (char const *file, struct timespec const timespec[2]) /* On Linux, lutimes is a thin wrapper around utimensat, so there is no point trying lutimes if utimensat failed with ENOSYS. */ -#if HAVE_LUTIMES && !HAVE_UTIMENSAT +# if HAVE_LUTIMES && !HAVE_UTIMENSAT { struct timeval timeval[2]; struct timeval *t; @@ -639,7 +667,7 @@ lutimens (char const *file, struct timespec const timespec[2]) if (result == 0 || errno != ENOSYS) return result; } -#endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */ +# endif /* HAVE_LUTIMES && !HAVE_UTIMENSAT */ /* Out of luck for symlinks, but we still handle regular files. */ if (!(adjustment_needed || REPLACE_FUNC_STAT_FILE) && lstat (file, &st)) @@ -648,5 +676,5 @@ lutimens (char const *file, struct timespec const timespec[2]) return fdutimens (-1, file, ts); errno = ENOSYS; return -1; -} #endif +} diff --git a/lib/utimens.h b/lib/utimens.h index e85477b8493..762c3f9a858 100644 --- a/lib/utimens.h +++ b/lib/utimens.h @@ -33,12 +33,16 @@ extern "C" { #endif int fdutimens (int, char const *, struct timespec const [2]); -#if !HAVE_UTIMENS + +#if HAVE_UTIMENS +# define utimens rpl_utimens +#endif int utimens (char const *, struct timespec const [2]); + +#if HAVE_LUTIMENS +# define lutimens rpl_lutimens #endif -#if !HAVE_LUTIMENS int lutimens (char const *, struct timespec const [2]); -#endif #ifdef __cplusplus } |
