aboutsummaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/Makefile1
-rw-r--r--lib/libc/Versions.def6
-rw-r--r--lib/libc/aarch64/string/timingsafe_memcmp.S2
-rw-r--r--lib/libc/gen/_rand48.c34
-rw-r--r--lib/libc/gen/drand48.c6
-rw-r--r--lib/libc/gen/erand48.c9
-rw-r--r--lib/libc/gen/fts-compat.c2
-rw-r--r--lib/libc/gen/fts-compat11.c2
-rw-r--r--lib/libc/gen/fts.3195
-rw-r--r--lib/libc/gen/fts.c3
-rw-r--r--lib/libc/gen/gen-compat.h48
-rw-r--r--lib/libc/gen/jrand48.c7
-rw-r--r--lib/libc/gen/lcong48.c12
-rw-r--r--lib/libc/gen/lrand48.c6
-rw-r--r--lib/libc/gen/mrand48.c8
-rw-r--r--lib/libc/gen/nrand48.c6
-rw-r--r--lib/libc/gen/psignal.39
-rw-r--r--lib/libc/gen/rand48.35
-rw-r--r--lib/libc/gen/rand48.h61
-rw-r--r--lib/libc/gen/seed48.c18
-rw-r--r--lib/libc/gen/srand48.c13
-rw-r--r--lib/libc/gen/sysconf.c2
-rw-r--r--lib/libc/include/port_before.h1
-rw-r--r--lib/libc/md/Makefile.inc3
-rw-r--r--lib/libc/nls/Makefile.inc5
-rw-r--r--lib/libc/resolv/Symbol.map1
-rw-r--r--lib/libc/resolv/res_init.c61
-rw-r--r--lib/libc/rpc/rpc_generic.c4
-rw-r--r--lib/libc/stdlib/Makefile.inc3
-rw-r--r--lib/libc/stdlib/Symbol.map4
-rw-r--r--lib/libc/stdlib/reallocarray.337
-rw-r--r--lib/libc/stdlib/reallocarray.c14
-rw-r--r--lib/libc/stdlib/recallocarray.c73
-rw-r--r--lib/libc/stdtime/Makefile.inc3
-rw-r--r--lib/libc/stdtime/ctime.339
-rw-r--r--lib/libc/stdtime/tzset.357
-rw-r--r--lib/libc/tests/stdtime/Makefile1
-rw-r--r--lib/libc/tests/stdtime/detect_tz_changes_test.c113
38 files changed, 614 insertions, 260 deletions
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
index d0c254e33396..8705568f6d34 100644
--- a/lib/libc/Makefile
+++ b/lib/libc/Makefile
@@ -109,7 +109,6 @@ NOASM=
.include "${LIBC_SRCTOP}/inet/Makefile.inc"
.include "${LIBC_SRCTOP}/isc/Makefile.inc"
.include "${LIBC_SRCTOP}/locale/Makefile.inc"
-.include "${LIBC_SRCTOP}/md/Makefile.inc"
.include "${LIBC_SRCTOP}/nameser/Makefile.inc"
.include "${LIBC_SRCTOP}/net/Makefile.inc"
.include "${LIBC_SRCTOP}/nls/Makefile.inc"
diff --git a/lib/libc/Versions.def b/lib/libc/Versions.def
index 184e107d225a..1c7b34bef35b 100644
--- a/lib/libc/Versions.def
+++ b/lib/libc/Versions.def
@@ -42,6 +42,10 @@ FBSD_1.7 {
FBSD_1.8 {
} FBSD_1.7;
+# This version was first added to 16.0-current.
+FBSD_1.9 {
+} FBSD_1.8;
+
# This is our private namespace. Any global interfaces that are
# strictly for use only by other FreeBSD applications and libraries
# are listed here. We use a separate namespace so we can write
@@ -49,4 +53,4 @@ FBSD_1.8 {
#
# Please do NOT increment the version of this namespace.
FBSDprivate_1.0 {
-} FBSD_1.8;
+} FBSD_1.9;
diff --git a/lib/libc/aarch64/string/timingsafe_memcmp.S b/lib/libc/aarch64/string/timingsafe_memcmp.S
index 28fdd911a387..4cc10a152aa8 100644
--- a/lib/libc/aarch64/string/timingsafe_memcmp.S
+++ b/lib/libc/aarch64/string/timingsafe_memcmp.S
@@ -114,4 +114,4 @@ ENTRY(timingsafe_memcmp)
csetm w0, lo
csinc w0, w0, wzr, ls
ret
-END(timingsafe_bcmp)
+END(timingsafe_memcmp)
diff --git a/lib/libc/gen/_rand48.c b/lib/libc/gen/_rand48.c
index 990e2c86949b..114c1595b33d 100644
--- a/lib/libc/gen/_rand48.c
+++ b/lib/libc/gen/_rand48.c
@@ -13,34 +13,6 @@
#include "rand48.h"
-unsigned short _rand48_seed[3] = {
- RAND48_SEED_0,
- RAND48_SEED_1,
- RAND48_SEED_2
-};
-unsigned short _rand48_mult[3] = {
- RAND48_MULT_0,
- RAND48_MULT_1,
- RAND48_MULT_2
-};
-unsigned short _rand48_add = RAND48_ADD;
-
-void
-_dorand48(unsigned short xseed[3])
-{
- unsigned long accu;
- unsigned short temp[2];
-
- accu = (unsigned long) _rand48_mult[0] * (unsigned long) xseed[0] +
- (unsigned long) _rand48_add;
- temp[0] = (unsigned short) accu; /* lower 16 bits */
- accu >>= sizeof(unsigned short) * 8;
- accu += (unsigned long) _rand48_mult[0] * (unsigned long) xseed[1] +
- (unsigned long) _rand48_mult[1] * (unsigned long) xseed[0];
- temp[1] = (unsigned short) accu; /* middle 16 bits */
- accu >>= sizeof(unsigned short) * 8;
- accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0];
- xseed[0] = temp[0];
- xseed[1] = temp[1];
- xseed[2] = (unsigned short) accu;
-}
+uint48 _rand48_seed = RAND48_SEED;
+uint48 _rand48_mult = RAND48_MULT;
+uint48 _rand48_add = RAND48_ADD;
diff --git a/lib/libc/gen/drand48.c b/lib/libc/gen/drand48.c
index cec04a6a2425..f7f43ff20468 100644
--- a/lib/libc/gen/drand48.c
+++ b/lib/libc/gen/drand48.c
@@ -13,10 +13,10 @@
#include "rand48.h"
-extern unsigned short _rand48_seed[3];
-
double
drand48(void)
{
- return erand48(_rand48_seed);
+ ERAND48_BEGIN;
+ _DORAND48(_rand48_seed);
+ ERAND48_END(_rand48_seed);
}
diff --git a/lib/libc/gen/erand48.c b/lib/libc/gen/erand48.c
index 286904c27839..38d4774a9fe6 100644
--- a/lib/libc/gen/erand48.c
+++ b/lib/libc/gen/erand48.c
@@ -16,8 +16,9 @@
double
erand48(unsigned short xseed[3])
{
- _dorand48(xseed);
- return ldexp((double) xseed[0], -48) +
- ldexp((double) xseed[1], -32) +
- ldexp((double) xseed[2], -16);
+ uint48 tmp;
+
+ ERAND48_BEGIN;
+ DORAND48(tmp, xseed);
+ ERAND48_END(tmp);
}
diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c
index f87cabf085f7..62a1e0a81f62 100644
--- a/lib/libc/gen/fts-compat.c
+++ b/lib/libc/gen/fts-compat.c
@@ -44,9 +44,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "gen-compat.h"
#include "fts-compat.h"
#include "un-namespace.h"
+#include "gen-compat.h"
#include "gen-private.h"
diff --git a/lib/libc/gen/fts-compat11.c b/lib/libc/gen/fts-compat11.c
index 0351ce5ac690..5abb378f5f08 100644
--- a/lib/libc/gen/fts-compat11.c
+++ b/lib/libc/gen/fts-compat11.c
@@ -43,9 +43,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "gen-compat.h"
#include "fts-compat11.h"
#include "un-namespace.h"
+#include "gen-compat.h"
#include "gen-private.h"
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
index ee558b892c8c..da304e59ee72 100644
--- a/lib/libc/gen/fts.3
+++ b/lib/libc/gen/fts.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 30, 2025
+.Dd October 6, 2025
.Dt FTS 3
.Os
.Sh NAME
@@ -69,14 +69,15 @@ on a file hierarchy, which is then supplied to
the other
.Nm
functions.
-The function
+The
.Fn fts_read
-returns a pointer to a structure describing one of the files in the file
-hierarchy.
-The function
+function returns a pointer to a structure describing one of the files
+in the file hierarchy.
+The
.Fn fts_children
-returns a pointer to a linked list of structures, each of which describes
-one of the files contained in a directory in the hierarchy.
+function returns a pointer to a linked list of structures, each of
+which describes one of the files contained in a directory in the
+hierarchy.
In general, directories are visited two distinguishable times; in pre-order
(before any of their descendants are visited) and in post-order (after all
of their descendants have been visited).
@@ -376,7 +377,44 @@ The
.Fa fts_name
field is always
.Dv NUL Ns -terminated .
-.Sh FTS_OPEN
+.Ss Thread Safety
+The
+.Nm
+functions can safely be used in multi-threaded programs provided no
+two threads access the same
+.Vt FTS
+or
+.Vt FTSENT
+structure simultaneously.
+However, unless the
+.Dv FTS_NOCHDIR
+flag was passed to
+.Fn fts_open
+or
+.Fn fts_open_b ,
+calls to
+.Fn fts_read
+and
+.Fn fts_children
+may change the current working directory, which will affect all
+threads.
+Conversely, changing the current working directory either during or
+between calls to
+.Fn fts_read
+or
+.Fn fts_children
+(even in a single-thread program) may cause
+.Nm
+to malfunction unless the
+.Dv FTS_NOCHDIR
+flag was passed to
+.Fn fts_open
+or
+.Fn fts_open_b
+and all paths in
+.Va path_argv
+were absolute.
+.Ss Fn fts_open
The
.Fn fts_open
function takes a pointer to an array of character pointers naming one
@@ -507,10 +545,10 @@ from descending into directories that have a different device number
than the file from which the descent began.
.El
.Pp
-The argument
-.Fn compar
-specifies a user-defined function which may be used to order the traversal
-of the hierarchy.
+The
+.Fa compar
+argument points to a user-defined function which may be used to order
+the traversal of the hierarchy.
It
takes two pointers to pointers to
.Vt FTSENT
@@ -545,7 +583,7 @@ the directory traversal order is in the order listed in
.Fa path_argv
for the root paths, and in the order listed in the directory for
everything else.
-.Sh FTS_OPEN_B
+.Ss Fn fts_open_b
The
.Fn fts_open_b
function is identical to
@@ -554,7 +592,7 @@ except that it takes a block pointer instead of a function pointer.
The block is copied before
.Fn fts_open_b
returns, so the original can safely go out of scope or be released.
-.Sh FTS_READ
+.Ss Fn fts_read
The
.Fn fts_read
function returns a pointer to an
@@ -588,6 +626,15 @@ structure is returned, and
.Va errno
may or may not have been set (see
.Fa fts_info ) .
+Note that
+.Fn fts_read
+will not set
+.Va errno
+to 0 if called again with the same
+.Fa ftsp
+argument after the
+.Dv FTS_STOP
+flag has been set or the end of the stream has been reached.
.Pp
The
.Vt FTSENT
@@ -602,10 +649,10 @@ directory, in which case they will not be overwritten until after a call to
.Fn fts_read
after the
.Vt FTSENT
-structure has been returned by the function
+structure has been returned by the
.Fn fts_read
-in post-order.
-.Sh FTS_CHILDREN
+function in post-order.
+.Ss Fn fts_children
The
.Fn fts_children
function returns a pointer to an
@@ -679,11 +726,11 @@ and
.Fa fts_namelen
fields.
.El
-.Sh FTS_SET
-The function
+.Ss Fn fts_set
+The
.Fn fts_set
-allows the user application to determine further processing for the
-file
+function allows the user application to determine further processing
+for the file
.Fa f
of the stream
.Fa ftsp .
@@ -749,7 +796,40 @@ The file may be one of those most recently returned by either
or
.Fn fts_read .
.El
-.Sh FTS_CLOSE
+.Ss Fn fts_set_clientptr , Fn fts_get_clientptr
+The
+.Fn fts_set_clientptr
+function sets the client data pointer for the stream
+.Fa ftsp
+to
+.Fa clientdata .
+The
+.Fn fts_get_clientptr
+function returns the client data pointer associated with
+.Fa ftsp .
+This can be used to pass per-stream data to the comparison function.
+.Pp
+For performance reasons,
+.Fn fts_get_clientptr
+may be shadowed by a preprocessor macro.
+.Ss Fn fts_get_stream
+The
+.Fn fts_get_stream
+function returns the
+.Nm
+stream associated with the file entry
+.Fa f .
+A typical use for this would be for a comparison function to first call
+.Fn fts_get_stream
+on one of its arguments, then call
+.Fn fts_get_clientptr
+to obtain the client data pointer, which in turn points to information
+necessary to correctly order the two entries.
+.Pp
+For performance reasons,
+.Fn fts_get_stream
+may be shadowed by a preprocessor macro.
+.Ss Fn fts_close
The
.Fn fts_close
function closes a file hierarchy stream
@@ -760,6 +840,75 @@ or
.Fn fts_open_b
was called to open
.Fa ftsp .
+.Sh RETURN VALUES
+The
+.Fn fts_open
+and
+.Fn fts_open_b
+functions return a pointer to the new
+.Nm
+stream on success and
+.Dv NULL
+on failure.
+.Pp
+The
+.Fn fts_read
+function returns a pointer to the next file entry on success, or if an
+error occurs that relates specifically to that file entry.
+On reaching the end of the file hierarchy, it returns
+.Dv NULL
+and sets the external variable
+.Va errno
+to 0.
+On failure, it returns
+.Dv NULL
+and sets
+.Va errno
+to an appropriate non-zero value.
+If called again after the
+.Dv FTS_STOP
+flag has been set or the end of the stream has been reached,
+.Fn fts_read
+returns
+.Dv NULL
+and leaves
+.Va errno
+untouched.
+.Pp
+The
+.Fn fts_children
+function returns a pointer to a linked list of file entries on
+success.
+On reaching the end of the file hierarchy, it returns
+.Dv NULL
+and sets the external variable
+.Va errno
+to 0.
+On failure, it returns
+.Dv NULL
+and sets
+.Va errno
+to an appropriate non-zero value.
+.Pp
+The
+.Fn fts_set
+function returns 0 on success and \-1 if its
+.Fa instr
+argument is invalid.
+.Pp
+The
+.Fn fts_get_clientptr
+function returns the client data pointer associated with its argument,
+or
+.Dv NULL
+if none has been set.
+.Pp
+The
+.Fn fts_get_stream
+function returns a pointer to the
+.Nm
+stream associated with its argument.
+.Pp
The
.Fn fts_close
function
@@ -816,7 +965,7 @@ functions may fail and set
as follows:
.Bl -tag -width Er
.It Bq Er EINVAL
-The options were invalid, or the list were empty.
+The options were invalid, or the list was empty.
.El
.Sh SEE ALSO
.Xr find 1 ,
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
index cce959ba836a..4aa386d777cd 100644
--- a/lib/libc/gen/fts.c
+++ b/lib/libc/gen/fts.c
@@ -106,7 +106,6 @@ struct _fts_private {
* This assumption only holds for UFS-like filesystems that implement
* links and directories this way, so we must punt for others.
*/
-
static const char *ufslike_filesystems[] = {
"ufs",
"zfs",
@@ -679,7 +678,6 @@ fts_children(FTS *sp, int instr)
void *
(fts_get_clientptr)(FTS *sp)
{
-
return (fts_get_clientptr(sp));
}
@@ -696,7 +694,6 @@ FTS *
void
fts_set_clientptr(FTS *sp, void *clientptr)
{
-
sp->fts_clientptr = clientptr;
}
diff --git a/lib/libc/gen/gen-compat.h b/lib/libc/gen/gen-compat.h
index 74678301af6f..19b9addb4321 100644
--- a/lib/libc/gen/gen-compat.h
+++ b/lib/libc/gen/gen-compat.h
@@ -40,24 +40,50 @@ struct freebsd11_statfs;
struct freebsd11_dirent *freebsd11_readdir(DIR *);
int freebsd11_readdir_r(DIR *, struct freebsd11_dirent *,
struct freebsd11_dirent **);
-int freebsd11_stat(const char *, struct freebsd11_stat *);
-int freebsd11_lstat(const char *, struct freebsd11_stat *);
-int freebsd11_fstat(int, struct freebsd11_stat *);
-int freebsd11_fstatat(int, const char *, struct freebsd11_stat *, int);
-int freebsd11_statfs(const char *, struct freebsd11_statfs *);
-int freebsd11_getfsstat(struct freebsd11_statfs *, long, int);
int freebsd11_getmntinfo(struct freebsd11_statfs **, int);
char *freebsd11_devname(__uint32_t dev, __mode_t type);
-char *freebsd11_devname_r(__uint32_t dev, __mode_t type, char *buf, int len);
+char *freebsd11_devname_r(__uint32_t dev, __mode_t type, char *buf,
+ int len);
-#define F14SG int freebsd14_setgroups(int gidsize, const __gid_t *gidset)
+/*
+ * We want freebsd11_fstat in C source to result in resolution to
+ * - fstat@FBSD_1.0 for libc.so (but we do not need the _definition_
+ * of this fstat, it is provided by libsys.so which we want to use).
+ * - freebsd11_fstat for libc.a (since if we make it fstat@FBSD_1.0
+ * for libc.a, then final linkage into static object ignores version
+ * and would reference fstat, which is the current syscall, not the
+ * compat syscall). libc.a provides the freebsd11_fstat implementation.
+ * Note that freebsd11_fstat from libc.a is not used for anything, but
+ * we make it correct nonetheless, just in case it would.
+ * This is arranged by COMPAT_SYSCALL, and libc can just use freebsd11_fstat.
+ */
#ifdef PIC
-static F14SG __attribute__((__weakref__("setgroups@FBSD_1.0")));
+#define COMPAT_SYSCALL(rtype, fun, args, sym, ver) \
+ rtype fun args; __sym_compat(sym, fun, ver);
#else
-F14SG;
+#define COMPAT_SYSCALL(rtype, fun, args, sym, ver) \
+ rtype fun args;
#endif
-#undef F14SG
+
+COMPAT_SYSCALL(int, freebsd11_stat, (const char *, struct freebsd11_stat *),
+ stat, FBSD_1.0);
+COMPAT_SYSCALL(int, freebsd11_lstat, (const char *, struct freebsd11_stat *),
+ lstat, FBSD_1.0);
+COMPAT_SYSCALL(int, freebsd11_fstat, (int, struct freebsd11_stat *),
+ fstat, FBSD_1.0);
+COMPAT_SYSCALL(int, freebsd11_fstatat, (int, const char *,
+ struct freebsd11_stat *, int), fstatat, FBSD_1.1);
+
+COMPAT_SYSCALL(int, freebsd11_statfs, (const char *,
+ struct freebsd11_statfs *), statfs, FBSD_1.0);
+COMPAT_SYSCALL(int, freebsd11_getfsstat, (struct freebsd11_statfs *, long,
+ int), getfsstat, FBSD_1.0);
+
+COMPAT_SYSCALL(int, freebsd14_setgroups, (int gidsize, const __gid_t *gidset),
+ setgroups, FBSD_1.0);
+
+#undef COMPAT_SYSCALL
#endif /* _GEN_COMPAT_H_ */
diff --git a/lib/libc/gen/jrand48.c b/lib/libc/gen/jrand48.c
index 0a9f780a9e5c..93442439d49e 100644
--- a/lib/libc/gen/jrand48.c
+++ b/lib/libc/gen/jrand48.c
@@ -11,14 +11,13 @@
* to anyone/anything when using this software.
*/
-#include <stdint.h>
-
#include "rand48.h"
long
jrand48(unsigned short xseed[3])
{
+ uint48 tmp;
- _dorand48(xseed);
- return ((int32_t)(((uint32_t)xseed[2] << 16) | (uint32_t)xseed[1]));
+ DORAND48(tmp, xseed);
+ return ((int)((tmp >> 16) & 0xffffffff));
}
diff --git a/lib/libc/gen/lcong48.c b/lib/libc/gen/lcong48.c
index f13826b3d3f3..871b2110ed94 100644
--- a/lib/libc/gen/lcong48.c
+++ b/lib/libc/gen/lcong48.c
@@ -13,18 +13,10 @@
#include "rand48.h"
-extern unsigned short _rand48_seed[3];
-extern unsigned short _rand48_mult[3];
-extern unsigned short _rand48_add;
-
void
lcong48(unsigned short p[7])
{
- _rand48_seed[0] = p[0];
- _rand48_seed[1] = p[1];
- _rand48_seed[2] = p[2];
- _rand48_mult[0] = p[3];
- _rand48_mult[1] = p[4];
- _rand48_mult[2] = p[5];
+ LOADRAND48(_rand48_seed, &p[0]);
+ LOADRAND48(_rand48_mult, &p[3]);
_rand48_add = p[6];
}
diff --git a/lib/libc/gen/lrand48.c b/lib/libc/gen/lrand48.c
index a3d0111cf4d5..cc07044b8af9 100644
--- a/lib/libc/gen/lrand48.c
+++ b/lib/libc/gen/lrand48.c
@@ -13,11 +13,9 @@
#include "rand48.h"
-extern unsigned short _rand48_seed[3];
-
long
lrand48(void)
{
- _dorand48(_rand48_seed);
- return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1);
+ _DORAND48(_rand48_seed);
+ return (_rand48_seed >> 17) & 0x7fffffff;
}
diff --git a/lib/libc/gen/mrand48.c b/lib/libc/gen/mrand48.c
index 15b0bfb1bd6e..f9128a6d4188 100644
--- a/lib/libc/gen/mrand48.c
+++ b/lib/libc/gen/mrand48.c
@@ -15,13 +15,9 @@
#include "rand48.h"
-extern unsigned short _rand48_seed[3];
-
long
mrand48(void)
{
-
- _dorand48(_rand48_seed);
- return ((int32_t)(((uint32_t)_rand48_seed[2] << 16) |
- (uint32_t)_rand48_seed[1]));
+ _DORAND48(_rand48_seed);
+ return ((int)((_rand48_seed >> 16) & 0xffffffff));
}
diff --git a/lib/libc/gen/nrand48.c b/lib/libc/gen/nrand48.c
index 6c54065e7e0f..f6f4e231105c 100644
--- a/lib/libc/gen/nrand48.c
+++ b/lib/libc/gen/nrand48.c
@@ -16,6 +16,8 @@
long
nrand48(unsigned short xseed[3])
{
- _dorand48(xseed);
- return ((long) xseed[2] << 15) + ((long) xseed[1] >> 1);
+ uint48 tmp;
+
+ DORAND48(tmp, xseed);
+ return ((tmp >> 17) & 0x7fffffff);
}
diff --git a/lib/libc/gen/psignal.3 b/lib/libc/gen/psignal.3
index 098b7b02a9b9..bf6a99b4b113 100644
--- a/lib/libc/gen/psignal.3
+++ b/lib/libc/gen/psignal.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 10, 2025
+.Dd September 23, 2025
.Dt PSIGNAL 3
.Os
.Sh NAME
@@ -141,6 +141,13 @@ The name in
can be either the name of the signal, with or without the
.Dq SIG
prefix, or a decimal number.
+.Sh RETURN VALUES
+The
+.Fn sig2str
+and
+.Fn str2sig
+return 0 on success and -1 on translation failure.
+In the latter case the memory to store the translation result is left intact.
.Sh SEE ALSO
.Xr sigaction 2 ,
.Xr perror 3 ,
diff --git a/lib/libc/gen/rand48.3 b/lib/libc/gen/rand48.3
index 1e47c843058e..3ea649354270 100644
--- a/lib/libc/gen/rand48.3
+++ b/lib/libc/gen/rand48.3
@@ -9,7 +9,7 @@
.\" of any kind. I shall in no event be liable for anything that happens
.\" to anyone/anything when using this software.
.\"
-.Dd September 4, 2012
+.Dd September 11, 2025
.Dt RAND48 3
.Os
.Sh NAME
@@ -183,5 +183,8 @@ generator calls.
.Xr arc4random 3 ,
.Xr rand 3 ,
.Xr random 3
+.Sh STANDARDS
+The functions described in this page are expected to conform to
+.St -p1003.1-2008 .
.Sh AUTHORS
.An Martin Birgmeier
diff --git a/lib/libc/gen/rand48.h b/lib/libc/gen/rand48.h
index 9861e99683cb..d3326e851491 100644
--- a/lib/libc/gen/rand48.h
+++ b/lib/libc/gen/rand48.h
@@ -14,10 +14,11 @@
#ifndef _RAND48_H_
#define _RAND48_H_
+#include <sys/types.h>
#include <math.h>
#include <stdlib.h>
-void _dorand48(unsigned short[3]);
+#include "fpmath.h"
#define RAND48_SEED_0 (0x330e)
#define RAND48_SEED_1 (0xabcd)
@@ -27,4 +28,62 @@ void _dorand48(unsigned short[3]);
#define RAND48_MULT_2 (0x0005)
#define RAND48_ADD (0x000b)
+typedef uint64_t uint48;
+
+extern uint48 _rand48_seed;
+extern uint48 _rand48_mult;
+extern uint48 _rand48_add;
+
+#define TOUINT48(x, y, z) \
+ ((uint48)(x) + (((uint48)(y)) << 16) + (((uint48)(z)) << 32))
+
+#define RAND48_SEED TOUINT48(RAND48_SEED_0, RAND48_SEED_1, RAND48_SEED_2)
+#define RAND48_MULT TOUINT48(RAND48_MULT_0, RAND48_MULT_1, RAND48_MULT_2)
+
+#define LOADRAND48(l, x) do { \
+ (l) = TOUINT48((x)[0], (x)[1], (x)[2]); \
+} while (0)
+
+#define STORERAND48(l, x) do { \
+ (x)[0] = (unsigned short)(l); \
+ (x)[1] = (unsigned short)((l) >> 16); \
+ (x)[2] = (unsigned short)((l) >> 32); \
+} while (0)
+
+#define _DORAND48(l) do { \
+ (l) = (l) * _rand48_mult + _rand48_add; \
+} while (0)
+
+#define DORAND48(l, x) do { \
+ LOADRAND48(l, x); \
+ _DORAND48(l); \
+ STORERAND48(l, x); \
+} while (0)
+
+#define ERAND48_BEGIN \
+ union { \
+ union IEEEd2bits ieee; \
+ uint64_t u64; \
+ } u; \
+ int s
+
+/*
+ * Optimization for speed: assume doubles are IEEE 754 and use bit fiddling
+ * rather than converting to double. Specifically, clamp the result to 48 bits
+ * and convert to a double in [0.0, 1.0) via division by 2^48. Normalize by
+ * shifting the most significant bit into the implicit one position and
+ * adjusting the exponent accordingly. The store to the exponent field
+ * overwrites the implicit one.
+ */
+#define ERAND48_END(x) do { \
+ u.u64 = ((x) & 0xffffffffffffULL); \
+ if (u.u64 == 0) \
+ return (0.0); \
+ u.u64 <<= 5; \
+ for (s = 0; !(u.u64 & (1LL << 52)); s++, u.u64 <<= 1) \
+ ; \
+ u.ieee.bits.exp = 1022 - s; \
+ return (u.ieee.d); \
+} while (0)
+
#endif /* _RAND48_H_ */
diff --git a/lib/libc/gen/seed48.c b/lib/libc/gen/seed48.c
index 258c4bac3c9f..f57656ce1121 100644
--- a/lib/libc/gen/seed48.c
+++ b/lib/libc/gen/seed48.c
@@ -13,24 +13,14 @@
#include "rand48.h"
-extern unsigned short _rand48_seed[3];
-extern unsigned short _rand48_mult[3];
-extern unsigned short _rand48_add;
-
unsigned short *
seed48(unsigned short xseed[3])
{
static unsigned short sseed[3];
- sseed[0] = _rand48_seed[0];
- sseed[1] = _rand48_seed[1];
- sseed[2] = _rand48_seed[2];
- _rand48_seed[0] = xseed[0];
- _rand48_seed[1] = xseed[1];
- _rand48_seed[2] = xseed[2];
- _rand48_mult[0] = RAND48_MULT_0;
- _rand48_mult[1] = RAND48_MULT_1;
- _rand48_mult[2] = RAND48_MULT_2;
+ STORERAND48(_rand48_seed, sseed);
+ LOADRAND48(_rand48_seed, xseed);
+ _rand48_mult = RAND48_MULT;
_rand48_add = RAND48_ADD;
- return sseed;
+ return (sseed);
}
diff --git a/lib/libc/gen/srand48.c b/lib/libc/gen/srand48.c
index fd369a094c51..4b82ece72db8 100644
--- a/lib/libc/gen/srand48.c
+++ b/lib/libc/gen/srand48.c
@@ -13,18 +13,11 @@
#include "rand48.h"
-extern unsigned short _rand48_seed[3];
-extern unsigned short _rand48_mult[3];
-extern unsigned short _rand48_add;
-
void
srand48(long seed)
{
- _rand48_seed[0] = RAND48_SEED_0;
- _rand48_seed[1] = (unsigned short) seed;
- _rand48_seed[2] = (unsigned short) (seed >> 16);
- _rand48_mult[0] = RAND48_MULT_0;
- _rand48_mult[1] = RAND48_MULT_1;
- _rand48_mult[2] = RAND48_MULT_2;
+ _rand48_seed = TOUINT48(RAND48_SEED_0, (unsigned short)seed,
+ (unsigned short)(seed >> 16));
+ _rand48_mult = RAND48_MULT;
_rand48_add = RAND48_ADD;
}
diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c
index 66562d0e29f0..b5b732eed05d 100644
--- a/lib/libc/gen/sysconf.c
+++ b/lib/libc/gen/sysconf.c
@@ -51,7 +51,7 @@
#include "un-namespace.h"
#include "../stdlib/atexit.h"
-#include "tzdir.h" /* from ../../../contrib/tzcode/stdtime */
+#include "tzdir.h" /* from ../../../contrib/tzcode */
#include "libc_private.h"
#define _PATH_ZONEINFO TZDIR /* from tzfile.h */
diff --git a/lib/libc/include/port_before.h b/lib/libc/include/port_before.h
index cfc43c53f157..aa2cd394104a 100644
--- a/lib/libc/include/port_before.h
+++ b/lib/libc/include/port_before.h
@@ -5,7 +5,6 @@
#define _LIBC 1
#define DO_PTHREADS 1
#define USE_POLL 1
-#define HAVE_MD5 1
#define ISC_SOCKLEN_T socklen_t
#define ISC_FORMAT_PRINTF(fmt, args) \
diff --git a/lib/libc/md/Makefile.inc b/lib/libc/md/Makefile.inc
deleted file mode 100644
index 82c5f0670485..000000000000
--- a/lib/libc/md/Makefile.inc
+++ /dev/null
@@ -1,3 +0,0 @@
-.PATH: ${SRCTOP}/sys/kern
-
-SRCS+= md5c.c
diff --git a/lib/libc/nls/Makefile.inc b/lib/libc/nls/Makefile.inc
index f26e04c187a5..c211026aba72 100644
--- a/lib/libc/nls/Makefile.inc
+++ b/lib/libc/nls/Makefile.inc
@@ -12,6 +12,11 @@ MAN+= catclose.3 catgets.3 catopen.3
# for translators.
NLSNAME= libc
+# We don't want libc's NLS catalogues to be installed in the clibs package.
+# Put them in locales instead, since anyone interested in NLS will have
+# that installed.
+NLSPACKAGE= locales
+
NLS+= be_BY.UTF-8
NLS+= ca_ES.ISO8859-1
NLS+= de_DE.ISO8859-1
diff --git a/lib/libc/resolv/Symbol.map b/lib/libc/resolv/Symbol.map
index 6b9c43298fb5..26daecbe2eff 100644
--- a/lib/libc/resolv/Symbol.map
+++ b/lib/libc/resolv/Symbol.map
@@ -103,6 +103,5 @@ FBSD_1.0 {
};
FBSD_1.4 {
- __res_rndinit;
__res_nrandomid;
};
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index 71ab2dcb7038..5a2fce013c8c 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -86,19 +86,6 @@
#include <unistd.h>
#include <netdb.h>
-#ifndef HAVE_MD5
-# include "../dst/md5.h"
-#else
-# ifdef SOLARIS2
-# include <sys/md5.h>
-# elif _LIBC
-# include <md5.h>
-# endif
-#endif
-#ifndef _MD5_H_
-# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
-#endif
-
#include "un-namespace.h"
#include "port_after.h"
@@ -184,8 +171,6 @@ __res_vinit(res_state statp, int preinit) {
statp->options = RES_DEFAULT;
}
- statp->_rnd = malloc(16);
- res_rndinit(statp);
statp->id = res_nrandomid(statp);
memset(u, 0, sizeof(u));
@@ -733,48 +718,18 @@ net_mask(struct in_addr in) /*!< XXX - should really use system's version of th
}
#endif
-static u_char srnd[16];
-
void
-res_rndinit(res_state statp)
+freebsd15_res_rndinit(res_state statp)
{
- struct timeval now;
- u_int32_t u32;
- u_int16_t u16;
- u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
-
- gettimeofday(&now, NULL);
- u32 = now.tv_sec;
- memcpy(rnd, &u32, 4);
- u32 = now.tv_usec;
- memcpy(rnd + 4, &u32, 4);
- u32 += now.tv_sec;
- memcpy(rnd + 8, &u32, 4);
- u16 = getpid();
- memcpy(rnd + 12, &u16, 2);
+ (void)statp;
}
+__sym_compat(__res_rndinit, freebsd15_res_rndinit, FBSD_1.4);
u_int
res_nrandomid(res_state statp) {
- struct timeval now;
- u_int16_t u16;
- MD5_CTX ctx;
- u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
-
- gettimeofday(&now, NULL);
- u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec);
- memcpy(rnd + 14, &u16, 2);
-#ifndef HAVE_MD5
- MD5_Init(&ctx);
- MD5_Update(&ctx, rnd, 16);
- MD5_Final(rnd, &ctx);
-#else
- MD5Init(&ctx);
- MD5Update(&ctx, rnd, 16);
- MD5Final(rnd, &ctx);
-#endif
- memcpy(&u16, rnd + 14, 2);
- return ((u_int) u16);
+ (void) statp;
+
+ return ((u_int)(arc4random() & 0xffff));
}
/*%
@@ -808,10 +763,6 @@ res_ndestroy(res_state statp) {
free(statp->_u._ext.ext);
statp->_u._ext.ext = NULL;
}
- if (statp->_rnd != NULL) {
- free(statp->_rnd);
- statp->_rnd = NULL;
- }
statp->options &= ~RES_INIT;
}
diff --git a/lib/libc/rpc/rpc_generic.c b/lib/libc/rpc/rpc_generic.c
index 0e563f6a5996..8019f2d8f236 100644
--- a/lib/libc/rpc/rpc_generic.c
+++ b/lib/libc/rpc/rpc_generic.c
@@ -610,6 +610,10 @@ __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
return NULL;
break;
#endif
+ case AF_NETLINK:
+ if (asprintf(&ret, "%s", (char *)nbuf->buf) < 0)
+ return NULL;
+ break;
case AF_LOCAL:
sun = nbuf->buf;
if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index ca199a669be1..e7b9955b9646 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -10,7 +10,7 @@ MISRCS+=C99_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \
merge.c mergesort_b.c ptsname.c qsort.c qsort_r.c qsort_r_compat.c \
qsort_s.c quick_exit.c radixsort.c rand.c \
- random.c reallocarray.c reallocf.c realpath.c remque.c \
+ random.c reallocarray.c reallocf.c realpath.c recallocarray.c remque.c \
set_constraint_handler_s.c strfmon.c strtoimax.c \
strtol.c strtold.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c \
strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
@@ -76,6 +76,7 @@ MLINKS+=random.3 initstate.3 \
random.3 srandom.3 \
random.3 srandomdev.3
MLINKS+=radixsort.3 sradixsort.3
+MLINKS+=reallocarray.3 recallocarray.3
MLINKS+=set_constraint_handler_s.3 abort_handler_s.3
MLINKS+=set_constraint_handler_s.3 ignore_handler_s.3
MLINKS+=strfmon.3 strfmon_l.3
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index 2b79ca2ece8b..53d71bcafb7d 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -131,6 +131,10 @@ FBSD_1.8 {
getenv_r;
};
+FBSD_1.9 {
+ recallocarray;
+};
+
FBSDprivate_1.0 {
__system;
_system;
diff --git a/lib/libc/stdlib/reallocarray.3 b/lib/libc/stdlib/reallocarray.3
index 80035c67a497..9a2ab5c7a840 100644
--- a/lib/libc/stdlib/reallocarray.3
+++ b/lib/libc/stdlib/reallocarray.3
@@ -26,7 +26,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 1, 2015
+.Dd October 2, 2025
.Dt REALLOCARRAY 3
.Os
.Sh NAME
@@ -38,6 +38,8 @@
.In stdlib.h
.Ft void *
.Fn reallocarray "void *ptr" "size_t nmemb" "size_t size"
+.Ft void *
+.Fn recallocarray "void *ptr" "size_t oldnmeb" "size_t nmemb" size_t size"
.Sh DESCRIPTION
The
.Fn reallocarray
@@ -52,6 +54,33 @@ and checks for integer overflow in the calculation
.Fa nmemb
*
.Fa size .
+.Pp
+The
+.Fn recallocarray
+function is similar to the
+.Fn reallocarray
+function
+except it ensures newly allocated memory is cleared similar to
+.Fn calloc .
+If
+.Fa ptr
+is
+.Dv NULL ,
+.Fa oldnmemb
+is ignored and the call is equivalent to
+.Fn calloc .
+If
+.Fa ptr
+is not
+.Dv NULL ,
+.Fa oldnmemb
+must be a value such that
+.Fa oldnmemb
+*
+.Fa size
+is the size of the earlier allocation that returned
+.Fa ptr ,
+otherwise the behaviour is undefined.
.Sh RETURN VALUES
The
.Fn reallocarray
@@ -142,3 +171,9 @@ function first appeared in
.Ox 5.6
and
.Fx 11.0 .
+The
+.Fn recallocarray
+function first appeared in
+.Ox 6.1
+and
+.Fx 16.0 .
diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c
index 0868804486cc..3632734c84de 100644
--- a/lib/libc/stdlib/reallocarray.c
+++ b/lib/libc/stdlib/reallocarray.c
@@ -17,23 +17,19 @@
#include <sys/types.h>
#include <errno.h>
+#include <stdckdint.h>
#include <stdint.h>
#include <stdlib.h>
-/*
- * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
- * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
- */
-#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
-
void *
reallocarray(void *optr, size_t nmemb, size_t size)
{
+ size_t nbytes;
- if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
- nmemb > 0 && SIZE_MAX / nmemb < size) {
+ if (ckd_mul(&nbytes, nmemb, size)) {
errno = ENOMEM;
return (NULL);
}
- return (realloc(optr, size * nmemb));
+
+ return (realloc(optr, nbytes));
}
diff --git a/lib/libc/stdlib/recallocarray.c b/lib/libc/stdlib/recallocarray.c
new file mode 100644
index 000000000000..cbf1fb2470cf
--- /dev/null
+++ b/lib/libc/stdlib/recallocarray.c
@@ -0,0 +1,73 @@
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdckdint.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+void *recallocarray(void *, size_t, size_t, size_t);
+
+void *
+recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
+{
+ size_t oldsize, newsize;
+ void *newptr;
+
+ if (ptr == NULL)
+ return calloc(newnmemb, size);
+
+ if (ckd_mul(&newsize, newnmemb, size)) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (ckd_mul(&oldsize, oldnmemb, size)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * Don't bother too much if we're shrinking just a bit,
+ * we do not shrink for series of small steps, oh well.
+ */
+ if (newsize <= oldsize) {
+ size_t d = oldsize - newsize;
+
+ if (d < oldsize / 2 && d < (size_t)getpagesize()) {
+ memset((char *)ptr + newsize, 0, d);
+ return ptr;
+ }
+ }
+
+ newptr = malloc(newsize);
+ if (newptr == NULL)
+ return NULL;
+
+ if (newsize > oldsize) {
+ memcpy(newptr, ptr, oldsize);
+ memset((char *)newptr + oldsize, 0, newsize - oldsize);
+ } else
+ memcpy(newptr, ptr, newsize);
+
+ explicit_bzero(ptr, oldsize);
+ free(ptr);
+
+ return newptr;
+}
diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc
index 647cbe6f40ba..1baa39a6c0a6 100644
--- a/lib/libc/stdtime/Makefile.inc
+++ b/lib/libc/stdtime/Makefile.inc
@@ -32,4 +32,5 @@ MLINKS+=strftime.3 strftime_l.3
MLINKS+=strptime.3 strptime_l.3
MLINKS+=time2posix.3 posix2time.3
MLINKS+=tzset.3 daylight.3 \
- tzset.3 timezone.3
+ tzset.3 timezone.3 \
+ tzset.3 tzname.3
diff --git a/lib/libc/stdtime/ctime.3 b/lib/libc/stdtime/ctime.3
index 96b7f775535a..6384e8bd959b 100644
--- a/lib/libc/stdtime/ctime.3
+++ b/lib/libc/stdtime/ctime.3
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 26, 2024
+.Dd September 23, 2025
.Dt CTIME 3
.Os
.Sh NAME
@@ -41,6 +41,8 @@
.Nm localtime ,
.Nm localtime_r ,
.Nm mktime ,
+.Nm offtime ,
+.Nm offtime_r ,
.Nm timegm
.Nd transform binary date and time values
.Sh LIBRARY
@@ -68,14 +70,19 @@
.Fn localtime_r "const time_t *clock" "struct tm *result"
.Ft time_t
.Fn mktime "struct tm *tm"
+.Ft struct tm *
+.Fn offtime "const time_t *clock" "long offset"
+.Ft struct tm *
+.Fn offtime_r "const time_t *clock" "long offset" "struct tm *result"
.Ft time_t
.Fn timegm "struct tm *tm"
.Sh DESCRIPTION
The
.Fn ctime ,
.Fn gmtime ,
+.Fn localtime ,
and
-.Fn localtime
+.Fn offtime
functions all take as argument a pointer to a time value representing
the time in seconds since the Epoch (00:00:00 UTC on January 1, 1970;
see
@@ -123,6 +130,18 @@ adjustment, and returns a pointer to a
.Vt struct tm .
.Pp
The
+.Fn offtime
+function similarly converts the time value with a time zone adjustment
+corresponding to the provided
+.Fa offset ,
+which is expressed in seconds, with positive values indicating a time
+zone ahead of UTC (east of the Prime Meridian).
+It does not call
+.Xr tzset 3
+or modify
+.Va tzname .
+.Pp
+The
.Fn ctime
function
adjusts the time value for the current time zone in the same manner as
@@ -155,13 +174,15 @@ except the caller must provide the output buffer
.Fa buf ,
which must be at least 26 characters long, to store the result in.
The
-.Fn localtime_r
+.Fn localtime_r ,
+.Fn gmtime_r ,
and
-.Fn gmtime_r
+.Fn offtime_r
functions provide the same functionality as
-.Fn localtime
+.Fn localtime ,
+.Fn gmtime ,
and
-.Fn gmtime
+.Fn offtime
respectively, except the caller must provide the output buffer
.Fa result .
.Pp
@@ -368,6 +389,12 @@ and
.Fn localtime_r
functions have been available since
.Fx 8.0 .
+The
+.Fn offtime
+and
+.Fn offtime_r
+functions were added in
+.Fx 15.0 .
.Sh BUGS
Except for
.Fn difftime ,
diff --git a/lib/libc/stdtime/tzset.3 b/lib/libc/stdtime/tzset.3
index 94ccbec9aba7..33e6a556306d 100644
--- a/lib/libc/stdtime/tzset.3
+++ b/lib/libc/stdtime/tzset.3
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 25, 2023
+.Dd September 30, 2025
.Dt TZSET 3
.Os
.Sh NAME
@@ -58,8 +58,8 @@ specifies how this is done.
.Pp
If
.Ev TZ
-does not appear in the environment, the best available approximation to
-local wall clock time, as specified by the
+does not appear in the environment, the best available approximation
+to local wall clock time, as specified by the
.Xr tzfile 5 Ns -format
file
.Pa /etc/localtime
@@ -68,9 +68,7 @@ is used.
If
.Ev TZ
appears in the environment but its value is a null string, Coordinated
-Universal Time
-.Pq Tn UTC
-is used (without leap second correction).
+Universal Time (UTC) is used (without leap second correction).
.Pp
If
.Ev TZ
@@ -81,13 +79,12 @@ the rest of its value is used as a pathname of a
file from which to read the time conversion information.
If the first character of the pathname is a slash
.Pq Ql /
-it is used as
-an absolute pathname; otherwise, it is used as a pathname relative to
-the system time conversion information directory.
+it is used as an absolute pathname; otherwise, it is used as a
+pathname relative to the system time conversion information directory.
.Pp
-If its value does not begin with a colon, it is first used as the pathname
-of a file (as described above) from which to read the time conversion
-information.
+If its value does not begin with a colon, it is first used as the
+pathname of a file (as described above) from which to read the time
+conversion information.
If that file cannot be read, the value is then interpreted as a direct
specification (the format is described below) of the time conversion
information.
@@ -96,24 +93,23 @@ If the
.Ev TZ
environment variable does not specify a
.Xr tzfile 5 Ns -format
-file and cannot be interpreted as a direct specification,
-.Tn UTC
-is used.
+file and cannot be interpreted as a direct specification, UTC is used.
.Pp
After the first call to
.Nm tzset ,
the
.Vt timezone
-variable is set to the difference, in seconds, between Coordinated Universal
-Time (UTC) and the local time.
+variable is set to the difference, in seconds, between Coordinated
+Universal Time (UTC) and the local time.
The
.Vt daylight
variable is set to 0 if the local timezone is observing standard time.
-It is set to 1 if the local timezone ever observes an alternate time, such as summer time.
+It is set to 1 if the local timezone ever observes an alternate time,
+such as summer time.
The first element of the
.Vt tzname
-array is the timezone name of standard time, while the second element is the
-name of the altnerative time zone.
+array is the timezone name of standard time, while the second element
+is the name of the altnerative time zone.
.Sh SPECIFICATION FORMAT
When
.Ev TZ
@@ -151,8 +147,7 @@ minus
.Pq Ql \- ,
plus
.Pq Ql + ,
-and
-.Tn ASCII
+and ASCII
.Dv NUL
are allowed.
.It Em offset
@@ -294,10 +289,8 @@ by the
file
.Em posixrules
in the system time conversion information directory are used, with the
-standard and summer time offsets from
-.Tn UTC
-replaced by those specified by
-the
+standard and summer time offsets from UTC replaced by those specified
+by the
.Em offset
values in
.Ev TZ .
@@ -315,20 +308,14 @@ local time zone file
.It Pa /usr/share/zoneinfo
time zone directory
.It Pa /usr/share/zoneinfo/posixrules
-rules for
-.Tn POSIX Ns -style
-.Tn TZ Ns 's
+rules for POSIX-style TZs
.It Pa /usr/share/zoneinfo/Etc/GMT
-for
-.Tn UTC
-leap seconds
+for UTC leap seconds
.El
.Pp
If the file
.Pa /usr/share/zoneinfo/UTC
-does not exist,
-.Tn UTC
-leap seconds are loaded from
+does not exist, UTC leap seconds are loaded from
.Pa /usr/share/zoneinfo/posixrules .
.Sh SEE ALSO
.Xr date 1 ,
diff --git a/lib/libc/tests/stdtime/Makefile b/lib/libc/tests/stdtime/Makefile
index 6b9068e1641b..590dea22da31 100644
--- a/lib/libc/tests/stdtime/Makefile
+++ b/lib/libc/tests/stdtime/Makefile
@@ -3,6 +3,7 @@
ATF_TESTS_C+= strptime_test
ATF_TESTS_C+= detect_tz_changes_test
+CFLAGS.detect_tz_changes_test+= -I${SRCTOP}/contrib/tzcode
.if ${MK_DETECT_TZ_CHANGES} != "no"
CFLAGS.detect_tz_changes_test+= -DDETECT_TZ_CHANGES
.endif
diff --git a/lib/libc/tests/stdtime/detect_tz_changes_test.c b/lib/libc/tests/stdtime/detect_tz_changes_test.c
index 6648d8498cc5..06c31c9fbc3d 100644
--- a/lib/libc/tests/stdtime/detect_tz_changes_test.c
+++ b/lib/libc/tests/stdtime/detect_tz_changes_test.c
@@ -20,12 +20,16 @@
#include <time.h>
#include <unistd.h>
+#include "tzdir.h"
+
#include <atf-c.h>
-static const struct tzcase {
+struct tzcase {
const char *tzfn;
const char *expect;
-} tzcases[] = {
+};
+
+static const struct tzcase tzcases[] = {
/*
* A handful of time zones and the expected result of
* strftime("%z (%Z)", tm) when that time zone is active
@@ -41,7 +45,8 @@ static const struct tzcase {
{ "UTC", "+0000 (UTC)" },
{ 0 },
};
-
+static const struct tzcase utc = { "UTC", "+0000 (UTC)" };
+static const struct tzcase invalid = { "invalid", "+0000 (-00)" };
static const time_t then = 1751328000; /* 2025-07-01 00:00:00 UTC */
static bool debugging;
@@ -62,9 +67,9 @@ debug(const char *fmt, ...)
static void
change_tz(const char *tzn)
{
- static const char *zfn = "/usr/share/zoneinfo";
- static const char *tfn = "root/etc/.localtime";
- static const char *dfn = "root/etc/localtime";
+ static const char *zfn = TZDIR;
+ static const char *tfn = "root" TZDEFAULT ".tmp";
+ static const char *dfn = "root" TZDEFAULT;
ssize_t clen;
int zfd, sfd, dfd;
@@ -96,6 +101,50 @@ test_tz(const char *expect)
ATF_CHECK_STREQ(expect, buf);
}
+ATF_TC(tz_default);
+ATF_TC_HEAD(tz_default, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test default zone");
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(tz_default, tc)
+{
+ /* prepare chroot with no /etc/localtime */
+ ATF_REQUIRE_EQ(0, mkdir("root", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755));
+ /* enter chroot */
+ ATF_REQUIRE_EQ(0, chroot("root"));
+ ATF_REQUIRE_EQ(0, chdir("/"));
+ /* check timezone */
+ unsetenv("TZ");
+ test_tz("+0000 (UTC)");
+}
+
+ATF_TC(tz_invalid_file);
+ATF_TC_HEAD(tz_invalid_file, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test invalid zone file");
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(tz_invalid_file, tc)
+{
+ static const char *dfn = "root/etc/localtime";
+ int fd;
+
+ /* prepare chroot with bogus /etc/localtime */
+ ATF_REQUIRE_EQ(0, mkdir("root", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755));
+ ATF_REQUIRE((fd = open(dfn, O_RDWR | O_CREAT, 0644)) >= 0);
+ ATF_REQUIRE_EQ(8, write(fd, "invalid\n", 8));
+ ATF_REQUIRE_EQ(0, close(fd));
+ /* enter chroot */
+ ATF_REQUIRE_EQ(0, chroot("root"));
+ ATF_REQUIRE_EQ(0, chdir("/"));
+ /* check timezone */
+ unsetenv("TZ");
+ test_tz(invalid.expect);
+}
+
ATF_TC(thin_jail);
ATF_TC_HEAD(thin_jail, tc)
{
@@ -320,6 +369,30 @@ test_tz_env(const char *tzval, const char *expect)
test_tz(expect);
}
+static void
+tz_env_common(void)
+{
+ char path[MAXPATHLEN];
+ const struct tzcase *tzcase = tzcases;
+ int len;
+
+ /* relative path */
+ for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++)
+ test_tz_env(tzcase->tzfn, tzcase->expect);
+ /* absolute path */
+ for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) {
+ len = snprintf(path, sizeof(path), "%s/%s", TZDIR, tzcase->tzfn);
+ ATF_REQUIRE(len > 0 && (size_t)len < sizeof(path));
+ test_tz_env(path, tzcase->expect);
+ }
+ /* absolute path with additional slashes */
+ for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++) {
+ len = snprintf(path, sizeof(path), "%s/////%s", TZDIR, tzcase->tzfn);
+ ATF_REQUIRE(len > 0 && (size_t)len < sizeof(path));
+ test_tz_env(path, tzcase->expect);
+ }
+}
+
ATF_TC(tz_env);
ATF_TC_HEAD(tz_env, tc)
{
@@ -327,10 +400,22 @@ ATF_TC_HEAD(tz_env, tc)
}
ATF_TC_BODY(tz_env, tc)
{
- const struct tzcase *tzcase;
+ tz_env_common();
+ /* escape from TZDIR is permitted when not setugid */
+ test_tz_env("../zoneinfo/UTC", utc.expect);
+}
- for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++)
- test_tz_env(tzcase->tzfn, tzcase->expect);
+
+ATF_TC(tz_invalid_env);
+ATF_TC_HEAD(tz_invalid_env, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test invalid TZ value");
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(tz_invalid_env, tc)
+{
+ test_tz_env("invalid", invalid.expect);
+ test_tz_env(":invalid", invalid.expect);
}
ATF_TC(setugid);
@@ -367,23 +452,25 @@ ATF_TC_HEAD(tz_env_setugid, tc)
}
ATF_TC_BODY(tz_env_setugid, tc)
{
- const struct tzcase *tzcase = tzcases;
-
ATF_REQUIRE_EQ(0, seteuid(UID_NOBODY));
ATF_REQUIRE(issetugid());
- for (tzcase = tzcases; tzcase->tzfn != NULL; tzcase++)
- test_tz_env(tzcase->tzfn, tzcase->expect);
+ tz_env_common();
+ /* escape from TZDIR is not permitted when setugid */
+ test_tz_env("../zoneinfo/UTC", invalid.expect);
}
ATF_TP_ADD_TCS(tp)
{
debugging = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
isatty(STDERR_FILENO);
+ ATF_TP_ADD_TC(tp, tz_default);
+ ATF_TP_ADD_TC(tp, tz_invalid_file);
ATF_TP_ADD_TC(tp, thin_jail);
#ifdef DETECT_TZ_CHANGES
ATF_TP_ADD_TC(tp, detect_tz_changes);
#endif /* DETECT_TZ_CHANGES */
ATF_TP_ADD_TC(tp, tz_env);
+ ATF_TP_ADD_TC(tp, tz_invalid_env);
ATF_TP_ADD_TC(tp, setugid);
ATF_TP_ADD_TC(tp, tz_env_setugid);
return (atf_no_error());