aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/gen/Symbol.map3
-rw-r--r--lib/libc/gen/elf_utils.c26
-rw-r--r--lib/libc/gen/err.c2
-rw-r--r--lib/libc/gen/fdopendir.c17
-rw-r--r--lib/libc/gen/fts.32
-rw-r--r--lib/libc/gen/gen-private.h4
-rw-r--r--lib/libc/gen/libc_interposing_table.c1
-rw-r--r--lib/libc/gen/opendir.c7
-rw-r--r--lib/libc/gen/opendir2.c15
-rw-r--r--lib/libc/gen/readdir.c11
-rw-r--r--lib/libc/gen/scandir.c6
-rw-r--r--lib/libc/gen/telldir.c4
-rw-r--r--lib/libc/gen/telldir.h6
-rw-r--r--lib/libc/gen/uexterr_format.c2
-rw-r--r--lib/libc/gen/wordexp.c10
-rw-r--r--lib/libc/include/libc_private.h4
-rw-r--r--lib/libc/powerpc64/gen/_ctx_start.S14
-rw-r--r--lib/libc/powerpc64/gen/makecontext.c3
-rw-r--r--lib/libc/stdio/fdopen.c18
-rw-r--r--lib/libc/stdio/freopen.c10
-rw-r--r--lib/libc/stdio/mktemp.37
-rw-r--r--lib/libc/stdio/mktemp.c2
-rw-r--r--lib/libc/stdtime/Makefile.inc1
-rw-r--r--lib/libc/stdtime/Symbol.map6
-rw-r--r--lib/libc/tests/gen/Makefile1
-rw-r--r--lib/libc/tests/gen/opendir_test.c145
-rw-r--r--lib/libc/tests/gen/scandir_test.c12
-rw-r--r--lib/libc/tests/gen/wordexp_test.c26
-rw-r--r--lib/libc/tests/stdtime/Makefile5
-rw-r--r--lib/libc/tests/stdtime/detect_tz_changes_test.c281
-rw-r--r--lib/libc/tests/sys/Makefile4
-rw-r--r--lib/libc/tests/sys/swapcontext_test.c63
-rw-r--r--lib/libcasper/services/cap_dns/tests/dns_test.c37
-rw-r--r--lib/libfetch/common.c7
-rw-r--r--lib/libnvmf/libnvmf.h6
-rw-r--r--lib/libnvmf/nvmf_host.c21
-rw-r--r--lib/libsecureboot/h/libsecureboot.h1
-rw-r--r--lib/libsys/fcntl.22
-rw-r--r--lib/libsys/fhopen.24
-rw-r--r--lib/libsys/getdirentries.210
-rw-r--r--lib/libsys/statfs.26
-rw-r--r--lib/libthr/pthread.map1
-rw-r--r--lib/libthr/thread/thr_list.c38
-rw-r--r--lib/libthr/thread/thr_private.h2
-rw-r--r--lib/libusb/libusb.343
-rw-r--r--lib/libusb/libusb.h28
-rw-r--r--lib/libusb/libusb10.c187
-rw-r--r--lib/libusb/libusb10.h30
-rw-r--r--lib/libusb/libusb10_desc.c11
-rw-r--r--lib/libusb/libusb10_hotplug.c18
-rw-r--r--lib/libusb/libusb10_io.c42
-rw-r--r--lib/libusb/libusb20_desc.h6
-rw-r--r--lib/ncurses/tinfo/Makefile9
53 files changed, 958 insertions, 269 deletions
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index 50dbf3425964..26f638568efc 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -458,8 +458,6 @@ FBSD_1.8 {
aio_read2;
aio_write2;
execvpe;
- fscandir;
- fscandir_b;
fdscandir;
fdscandir_b;
fts_open_b;
@@ -598,7 +596,6 @@ FBSDprivate_1.0 {
__libc_tcdrain;
- __pthread_distribute_static_tls;
__pthread_map_stacks_exec;
__fillcontextx;
__fillcontextx2;
diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c
index 330aa8f17f7e..3714a0dc42b5 100644
--- a/lib/libc/gen/elf_utils.c
+++ b/lib/libc/gen/elf_utils.c
@@ -41,7 +41,6 @@
#include "libc_private.h"
void __pthread_map_stacks_exec(void);
-void __pthread_distribute_static_tls(size_t, void *, size_t, size_t);
int
__elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr)
@@ -105,28 +104,3 @@ __pthread_map_stacks_exec(void)
((void (*)(void))__libc_interposing[INTERPOS_map_stacks_exec])();
}
-
-void
-__libc_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- char *tlsbase;
-
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)_tcb_get() + offset;
-#else
- tlsbase = (char *)_tcb_get() - offset;
-#endif
- memcpy(tlsbase, src, len);
- memset(tlsbase + len, 0, total_len - len);
-}
-
-#pragma weak __pthread_distribute_static_tls
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
-
- ((void (*)(size_t, void *, size_t, size_t))__libc_interposing[
- INTERPOS_distribute_static_tls])(offset, src, len, total_len);
-}
diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c
index cdce20af5a91..16cbe27693e7 100644
--- a/lib/libc/gen/err.c
+++ b/lib/libc/gen/err.c
@@ -119,7 +119,7 @@ vexterr(bool doexterr, int code, const char *fmt, va_list ap)
fprintf(err_file, ": ");
}
fprintf(err_file, "%s", strerror(code));
- if (doexterr && extstatus == 0)
+ if (doexterr && extstatus == 0 && exterr[0] != '\0')
fprintf(err_file, " (extended error %s)", exterr);
fprintf(err_file, "\n");
}
diff --git a/lib/libc/gen/fdopendir.c b/lib/libc/gen/fdopendir.c
index 67c0766b6d83..9393cbe28f85 100644
--- a/lib/libc/gen/fdopendir.c
+++ b/lib/libc/gen/fdopendir.c
@@ -30,14 +30,13 @@
*/
#include "namespace.h"
-#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
+#include <stdbool.h>
#include "un-namespace.h"
#include "gen-private.h"
@@ -49,8 +48,16 @@
DIR *
fdopendir(int fd)
{
+ int flags, rc;
- if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ flags = _fcntl(fd, F_GETFD, 0);
+ if (flags == -1)
return (NULL);
+
+ if ((flags & FD_CLOEXEC) == 0) {
+ rc = _fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ if (rc == -1)
+ return (NULL);
+ }
return (__opendir_common(fd, DTF_HIDEW | DTF_NODUP, true));
}
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
index 5860d1be1a1e..ee558b892c8c 100644
--- a/lib/libc/gen/fts.3
+++ b/lib/libc/gen/fts.3
@@ -394,7 +394,7 @@ must be specified.
The options are selected by
.Em or Ns 'ing
the following values:
-.Bl -tag -width "FTS_PHYSICAL"
+.Bl -tag -width "FTS_COMFOLLOWDIR"
.It Dv FTS_COMFOLLOW
This option causes any symbolic link specified as a root path to be
followed immediately whether or not
diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h
index 3792a61ff942..b6749b3435cd 100644
--- a/lib/libc/gen/gen-private.h
+++ b/lib/libc/gen/gen-private.h
@@ -43,8 +43,8 @@ struct pthread_mutex;
*/
struct _dirdesc {
int dd_fd; /* file descriptor associated with directory */
- long dd_loc; /* offset in current buffer */
- long dd_size; /* amount of data returned by getdirentries */
+ size_t dd_loc; /* offset in current buffer */
+ size_t dd_size; /* amount of data returned by getdirentries */
char *dd_buf; /* data buffer */
int dd_len; /* size of data buffer */
off_t dd_seek; /* magic cookie returned by getdirentries */
diff --git a/lib/libc/gen/libc_interposing_table.c b/lib/libc/gen/libc_interposing_table.c
index 8eae6c7f5d95..025a67ac3eac 100644
--- a/lib/libc/gen/libc_interposing_table.c
+++ b/lib/libc/gen/libc_interposing_table.c
@@ -42,7 +42,6 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(spinlock, __libc_spinlock_stub),
SLOT(spinunlock, __libc_spinunlock_stub),
SLOT(map_stacks_exec, __libc_map_stacks_exec),
- SLOT(distribute_static_tls, __libc_distribute_static_tls),
SLOT(uexterr_gettext, __libc_uexterr_gettext),
};
#undef SLOT
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c
index 956c92c321e8..08d9eb10eaa2 100644
--- a/lib/libc/gen/opendir.c
+++ b/lib/libc/gen/opendir.c
@@ -30,14 +30,7 @@
*/
#include "namespace.h"
-#include <sys/param.h>
-
#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "un-namespace.h"
#include "gen-private.h"
diff --git a/lib/libc/gen/opendir2.c b/lib/libc/gen/opendir2.c
index b9ac23e6d9fd..c5c2e662efd8 100644
--- a/lib/libc/gen/opendir2.c
+++ b/lib/libc/gen/opendir2.c
@@ -30,11 +30,12 @@
*/
#include "namespace.h"
-#include <sys/param.h>
+#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -52,8 +53,7 @@ __opendir2(const char *name, int flags)
if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0)
return (NULL);
- if ((fd = _open(name,
- O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)) == -1)
+ if ((fd = _open(name, O_DIRECTORY | O_RDONLY | O_CLOEXEC)) == -1)
return (NULL);
dir = __opendir_common(fd, flags, false);
@@ -264,6 +264,7 @@ DIR *
__opendir_common(int fd, int flags, bool use_current_pos)
{
DIR *dirp;
+ ssize_t ret;
int incr;
int saved_errno;
bool unionstack;
@@ -313,13 +314,11 @@ __opendir_common(int fd, int flags, bool use_current_pos)
* to prime dd_seek. This also checks if the
* fd passed to fdopendir() is a directory.
*/
- dirp->dd_size = _getdirentries(dirp->dd_fd,
+ ret = _getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size < 0) {
- if (errno == EINVAL)
- errno = ENOTDIR;
+ if (ret < 0)
goto fail;
- }
+ dirp->dd_size = (size_t)ret;
dirp->dd_flags |= __DTF_SKIPREAD;
} else {
dirp->dd_size = 0;
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
index 2a2fa999b7ce..b70102954df1 100644
--- a/lib/libc/gen/readdir.c
+++ b/lib/libc/gen/readdir.c
@@ -48,8 +48,9 @@ struct dirent *
_readdir_unlocked(DIR *dirp, int flags)
{
struct dirent *dp;
- long initial_seek;
- long initial_loc = 0;
+ off_t initial_seek;
+ size_t initial_loc = 0;
+ ssize_t ret;
for (;;) {
if (dirp->dd_loc >= dirp->dd_size) {
@@ -61,11 +62,13 @@ _readdir_unlocked(DIR *dirp, int flags)
}
if (dirp->dd_loc == 0 &&
!(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) {
+ dirp->dd_size = 0;
initial_seek = dirp->dd_seek;
- dirp->dd_size = _getdirentries(dirp->dd_fd,
+ ret = _getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size <= 0)
+ if (ret <= 0)
return (NULL);
+ dirp->dd_size = (size_t)ret;
_fixtelldir(dirp, initial_seek, initial_loc);
}
dirp->dd_flags &= ~__DTF_SKIPREAD;
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index 8e62fe980868..fb589f4b36b6 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -252,9 +252,3 @@ scandir_thunk_cmp(const void *p1, const void *p2, void *thunk)
return (dc((const struct dirent **)p1, (const struct dirent **)p2));
}
#endif
-
-#ifdef I_AM_SCANDIR_B
-__weak_reference(fdscandir_b, fscandir_b);
-#else
-__weak_reference(fdscandir, fscandir);
-#endif
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index b751fafd975f..1731cc4d7a2c 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -118,7 +118,7 @@ _seekdir(DIR *dirp, long loc)
struct dirent *dp;
union ddloc_packed ddloc;
off_t loc_seek;
- long loc_loc;
+ size_t loc_loc;
ddloc.l = loc;
@@ -171,7 +171,7 @@ _seekdir(DIR *dirp, long loc)
* fetching a new block to fix any such telldir locations.
*/
void
-_fixtelldir(DIR *dirp, long oldseek, long oldloc)
+_fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc)
{
struct ddloc_mem *lp;
diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h
index 6d113491e819..02fd52af9060 100644
--- a/lib/libc/gen/telldir.h
+++ b/lib/libc/gen/telldir.h
@@ -46,9 +46,9 @@
*/
struct ddloc_mem {
LIST_ENTRY(ddloc_mem) loc_lqe; /* entry in list */
- long loc_index; /* key associated with structure */
+ size_t loc_index; /* key associated with structure */
off_t loc_seek; /* magic cookie returned by getdirentries */
- long loc_loc; /* offset of entry in buffer */
+ size_t loc_loc; /* offset of entry in buffer */
};
#ifdef __LP64__
@@ -102,7 +102,7 @@ bool _filldir(DIR *, bool);
struct dirent *_readdir_unlocked(DIR *, int);
void _reclaim_telldir(DIR *);
void _seekdir(DIR *, long);
-void _fixtelldir(DIR *dirp, long oldseek, long oldloc);
+void _fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc);
DIR *__opendir_common(int, int, bool);
#define RDU_SKIP 0x0001
diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c
index 86ba40234ae4..e8ddfbd578e3 100644
--- a/lib/libc/gen/uexterr_format.c
+++ b/lib/libc/gen/uexterr_format.c
@@ -20,7 +20,7 @@ __uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz)
if (bufsz > UEXTERROR_MAXLEN)
bufsz = UEXTERROR_MAXLEN;
if (ue->error == 0) {
- strlcpy(buf, "No error", bufsz);
+ strlcpy(buf, "", bufsz);
return (0);
}
if (ue->msg[0] == '\0') {
diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
index f1437e30bbe2..f8080c20d121 100644
--- a/lib/libc/gen/wordexp.c
+++ b/lib/libc/gen/wordexp.c
@@ -265,7 +265,15 @@ cleanup:
errno = serrno;
return (error);
}
- if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ /*
+ * Check process exit status, but ignore ECHILD as the child may have
+ * been automatically reaped if the process had set SIG_IGN or
+ * SA_NOCLDWAIT for SIGCHLD, and our reason for waitpid was just to
+ * reap our own child on behalf of the calling process.
+ */
+ if (wpid < 0 && errno != ECHILD)
+ return (WRDE_NOSPACE); /* abort for unknown reason */
+ if (wpid >= 0 && (!WIFEXITED(status) || WEXITSTATUS(status) != 0))
return (WRDE_NOSPACE); /* abort for unknown reason */
/*
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 1bc22f3931a5..db4cbc32be35 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -249,7 +249,7 @@ enum {
INTERPOS_map_stacks_exec,
INTERPOS_fdatasync,
INTERPOS_clock_nanosleep,
- INTERPOS_distribute_static_tls,
+ INTERPOS__reserved0, /* was distribute_static_tls */
INTERPOS_pdfork,
INTERPOS_uexterr_gettext,
INTERPOS_MAX
@@ -361,8 +361,6 @@ struct dl_phdr_info;
int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
void __init_elf_aux_vector(void);
void __libc_map_stacks_exec(void);
-void __libc_distribute_static_tls(__size_t, void *, __size_t, __size_t);
-__uintptr_t __libc_static_tls_base(__size_t);
void _pthread_cancel_enter(int);
void _pthread_cancel_leave(int);
diff --git a/lib/libc/powerpc64/gen/_ctx_start.S b/lib/libc/powerpc64/gen/_ctx_start.S
index c2f8abfd6486..98225f9c1138 100644
--- a/lib/libc/powerpc64/gen/_ctx_start.S
+++ b/lib/libc/powerpc64/gen/_ctx_start.S
@@ -34,6 +34,16 @@
ld %r2,8(%r14)
ld %r14,0(%r14)
#else
+ /*
+ * The stack frame was already set up in makecontext(),
+ * so we can safely use the guaranteed fields here.
+ *
+ * Note we do step on the allocated stack frame's TOC,
+ * but since we never return from this function (i.e.
+ * never restore the stack frame) this should be safe.
+ */
+ std %r2,24(%r1) /* save TOC */
+
/* Load global entry point */
mr %r12,%r14
#endif
@@ -41,6 +51,10 @@
blrl /* branch to start function */
mr %r3,%r15 /* pass pointer to ucontext as argument */
nop
+#if defined(_CALL_ELF) && _CALL_ELF != 1
+ /* Restore TOC */
+ ld %r2,24(%r1)
+#endif
bl CNAME(_ctx_done) /* branch to ctxt completion func */
/*
* we should never return from the
diff --git a/lib/libc/powerpc64/gen/makecontext.c b/lib/libc/powerpc64/gen/makecontext.c
index 75c2d40bdd60..9e3a976fa1bd 100644
--- a/lib/libc/powerpc64/gen/makecontext.c
+++ b/lib/libc/powerpc64/gen/makecontext.c
@@ -78,7 +78,7 @@ __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
*/
stackargs = (argc > 8) ? argc - 8 : 0;
sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size
- - sizeof(uintptr_t)*(stackargs + 2);
+ - sizeof(uintptr_t)*(stackargs + 6);
sp = (char *)((uintptr_t)sp & ~0x1f);
mc = &ucp->uc_mcontext;
@@ -119,6 +119,7 @@ __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
mc->mc_srr0 = *(uintptr_t *)_ctx_start;
#else
mc->mc_srr0 = (uintptr_t) _ctx_start;
+ mc->mc_gpr[12] = (uintptr_t) _ctx_start;/* required for prologue */
#endif
mc->mc_gpr[1] = (uintptr_t) sp; /* new stack pointer */
mc->mc_gpr[14] = (uintptr_t) start; /* r14 <- start */
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c
index a0d7b71df782..49ec97eda39d 100644
--- a/lib/libc/stdio/fdopen.c
+++ b/lib/libc/stdio/fdopen.c
@@ -46,7 +46,7 @@ FILE *
fdopen(int fd, const char *mode)
{
FILE *fp;
- int flags, oflags, fdflags, tmp;
+ int flags, oflags, fdflags, rc, tmp;
/*
* File descriptors are a full int, but _file is only a short.
@@ -76,9 +76,19 @@ fdopen(int fd, const char *mode)
if ((fp = __sfp()) == NULL)
return (NULL);
- if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
- fp->_flags = 0;
- return (NULL);
+ if ((oflags & O_CLOEXEC) != 0) {
+ tmp = _fcntl(fd, F_GETFD, 0);
+ if (tmp == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+ if ((tmp & FD_CLOEXEC) == 0) {
+ rc = _fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
+ if (rc == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+ }
}
fp->_flags = flags;
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
index f0732b6d6741..048fd30b3193 100644
--- a/lib/libc/stdio/freopen.c
+++ b/lib/libc/stdio/freopen.c
@@ -55,7 +55,7 @@ freopen(const char * __restrict file, const char * __restrict mode,
FILE * __restrict fp)
{
int f;
- int dflags, flags, isopen, oflags, sverrno, wantfd;
+ int dflags, fdflags, flags, isopen, oflags, sverrno, wantfd;
if ((flags = __sflags(mode, &oflags)) == 0) {
sverrno = errno;
@@ -113,8 +113,12 @@ freopen(const char * __restrict file, const char * __restrict mode,
(void) ftruncate(fp->_file, (off_t)0);
if (!(oflags & O_APPEND))
(void) _sseek(fp, (fpos_t)0, SEEK_SET);
- if (oflags & O_CLOEXEC)
- (void) _fcntl(fp->_file, F_SETFD, FD_CLOEXEC);
+ if ((oflags & O_CLOEXEC) != 0) {
+ fdflags = _fcntl(fp->_file, F_GETFD, 0);
+ if (fdflags != -1 && (fdflags & FD_CLOEXEC) == 0)
+ (void) _fcntl(fp->_file, F_SETFD,
+ fdflags | FD_CLOEXEC);
+ }
f = fp->_file;
isopen = 0;
wantfd = -1;
diff --git a/lib/libc/stdio/mktemp.3 b/lib/libc/stdio/mktemp.3
index 2b8b2d6c9e44..8d38dd2cd57e 100644
--- a/lib/libc/stdio/mktemp.3
+++ b/lib/libc/stdio/mktemp.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 29, 2019
+.Dd July 07, 2025
.Dt MKTEMP 3
.Os
.Sh NAME
@@ -101,9 +101,10 @@ The permitted flags are
.Dv O_DIRECT ,
.Dv O_SHLOCK ,
.Dv O_EXLOCK ,
-.Dv O_SYNC
+.Dv O_SYNC ,
+.Dv O_CLOEXEC
and
-.Dv O_CLOEXEC .
+.Dv O_CLOFORK .
.Pp
The
.Fn mkstemps
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
index 8aff226acf14..a2f80ee7b0dd 100644
--- a/lib/libc/stdio/mktemp.c
+++ b/lib/libc/stdio/mktemp.c
@@ -121,7 +121,7 @@ _gettemp(int dfd, char *path, int *doopen, int domkdir, int slen, int oflags)
if ((doopen != NULL && domkdir) || slen < 0 ||
(oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
- O_CLOEXEC)) != 0) {
+ O_CLOEXEC | O_CLOFORK)) != 0) {
errno = EINVAL;
return (0);
}
diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc
index 5d0ce7765b63..647cbe6f40ba 100644
--- a/lib/libc/stdtime/Makefile.inc
+++ b/lib/libc/stdtime/Makefile.inc
@@ -18,6 +18,7 @@ CFLAGS.${src}+= -I${LIBC_SRCTOP}/stdtime
CFLAGS.localtime.c+= -DALL_STATE -DTHREAD_SAFE
.if ${MK_DETECT_TZ_CHANGES} != "no"
CFLAGS.localtime.c+= -DDETECT_TZ_CHANGES
+CFLAGS.Version.map+= -DDETECT_TZ_CHANGES
.endif
MAN+= ctime.3 strftime.3 strptime.3 time2posix.3 tzset.3
diff --git a/lib/libc/stdtime/Symbol.map b/lib/libc/stdtime/Symbol.map
index 669d4d47907b..6a34cd3ea590 100644
--- a/lib/libc/stdtime/Symbol.map
+++ b/lib/libc/stdtime/Symbol.map
@@ -35,3 +35,9 @@ FBSD_1.8 {
daylight;
timezone;
};
+
+FBSDprivate_1.0 {
+#ifdef DETECT_TZ_CHANGES
+ __tz_change_interval;
+#endif
+};
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile
index a967ad5ddf91..8c2151105209 100644
--- a/lib/libc/tests/gen/Makefile
+++ b/lib/libc/tests/gen/Makefile
@@ -20,6 +20,7 @@ ATF_TESTS_C+= glob2_test
ATF_TESTS_C+= glob_blocks_test
.endif
ATF_TESTS_C+= makecontext_test
+ATF_TESTS_C+= opendir_test
ATF_TESTS_C+= popen_test
ATF_TESTS_C+= posix_spawn_test
ATF_TESTS_C+= realpath2_test
diff --git a/lib/libc/tests/gen/opendir_test.c b/lib/libc/tests/gen/opendir_test.c
new file mode 100644
index 000000000000..b7481255654f
--- /dev/null
+++ b/lib/libc/tests/gen/opendir_test.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+/*
+ * Create a directory with a single subdirectory.
+ */
+static void
+opendir_prepare(const struct atf_tc *tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/subdir", 0755));
+}
+
+/*
+ * Assuming dirp represents the directory created by opendir_prepare(),
+ * verify that readdir() returns what we expected to see there.
+ */
+static void
+opendir_check(const struct atf_tc *tc, DIR *dirp)
+{
+ struct dirent *ent;
+
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(1, ent->d_namlen);
+ ATF_CHECK_STREQ(".", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(2, ent->d_namlen);
+ ATF_CHECK_STREQ("..", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(sizeof("subdir") - 1, ent->d_namlen);
+ ATF_CHECK_STREQ("subdir", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_CHECK(readdir(dirp) == NULL);
+ ATF_CHECK(readdir(dirp) == NULL);
+}
+
+ATF_TC(opendir_ok);
+ATF_TC_HEAD(opendir_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Open a directory.");
+}
+ATF_TC_BODY(opendir_ok, tc)
+{
+ DIR *dirp;
+
+ opendir_prepare(tc);
+ ATF_REQUIRE((dirp = opendir("dir")) != NULL);
+ opendir_check(tc, dirp);
+ ATF_CHECK_EQ(0, closedir(dirp));
+}
+
+ATF_TC(opendir_fifo);
+ATF_TC_HEAD(opendir_fifo, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Do not hang if given a named pipe.");
+}
+ATF_TC_BODY(opendir_fifo, tc)
+{
+ DIR *dirp;
+ int fd;
+
+ ATF_REQUIRE((fd = mkfifo("fifo", 0644)) >= 0);
+ ATF_REQUIRE_EQ(0, close(fd));
+ ATF_REQUIRE((dirp = opendir("fifo")) == NULL);
+ ATF_CHECK_EQ(ENOTDIR, errno);
+}
+
+ATF_TC(fdopendir_ok);
+ATF_TC_HEAD(fdopendir_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from a directory descriptor.");
+}
+ATF_TC_BODY(fdopendir_ok, tc)
+{
+ DIR *dirp;
+ int dd;
+
+ opendir_prepare(tc);
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE((dirp = fdopendir(dd)) != NULL);
+ opendir_check(tc, dirp);
+ ATF_CHECK_EQ(dd, fdclosedir(dirp));
+ ATF_CHECK_EQ(0, close(dd));
+}
+
+ATF_TC(fdopendir_ebadf);
+ATF_TC_HEAD(fdopendir_ebadf, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from an invalid descriptor.");
+}
+ATF_TC_BODY(fdopendir_ebadf, tc)
+{
+ DIR *dirp;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_CHECK_EQ(0, close(dd));
+ ATF_REQUIRE((dirp = fdopendir(dd)) == NULL);
+ ATF_CHECK_EQ(EBADF, errno);
+}
+
+ATF_TC(fdopendir_enotdir);
+ATF_TC_HEAD(fdopendir_enotdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from a non-directory descriptor.");
+}
+ATF_TC_BODY(fdopendir_enotdir, tc)
+{
+ DIR *dirp;
+ int fd;
+
+ ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0);
+ ATF_REQUIRE((dirp = fdopendir(fd)) == NULL);
+ ATF_CHECK_EQ(ENOTDIR, errno);
+ ATF_CHECK_EQ(0, close(fd));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, opendir_ok);
+ ATF_TP_ADD_TC(tp, fdopendir_ok);
+ ATF_TP_ADD_TC(tp, fdopendir_ebadf);
+ ATF_TP_ADD_TC(tp, fdopendir_enotdir);
+ ATF_TP_ADD_TC(tp, opendir_fifo);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/scandir_test.c b/lib/libc/tests/gen/scandir_test.c
index f7b52b5e3616..afd25bf7c0b2 100644
--- a/lib/libc/tests/gen/scandir_test.c
+++ b/lib/libc/tests/gen/scandir_test.c
@@ -157,7 +157,7 @@ ATF_TC_BODY(scandir_error, tc)
{
char path[16];
struct dirent **namelist = NULL;
- int fd, i, ret;
+ int fd, i;
ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
for (i = 0; i < 1024; i++) {
@@ -170,9 +170,8 @@ ATF_TC_BODY(scandir_error, tc)
scandir_error_count = 0;
scandir_error_fd = fd;
scandir_error_select_return = 0;
- ret = fdscandir(fd, &namelist, scandir_error_select, NULL);
- ATF_CHECK_EQ(-1, ret);
- ATF_CHECK_ERRNO(EBADF, ret < 0);
+ ATF_CHECK_ERRNO(EBADF,
+ fdscandir(fd, &namelist, scandir_error_select, NULL) < 0);
ATF_CHECK_EQ(NULL, namelist);
/* second pass, select everything */
@@ -180,9 +179,8 @@ ATF_TC_BODY(scandir_error, tc)
scandir_error_count = 0;
scandir_error_fd = fd;
scandir_error_select_return = 1;
- ret = fdscandir(fd, &namelist, scandir_error_select, NULL);
- ATF_CHECK_EQ(-1, ret);
- ATF_CHECK_ERRNO(EBADF, ret < 0);
+ ATF_CHECK_ERRNO(EBADF,
+ fdscandir(fd, &namelist, scandir_error_select, NULL) < 0);
ATF_CHECK_EQ(NULL, namelist);
}
diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c
index 909097fbf51e..a8b9d5509633 100644
--- a/lib/libc/tests/gen/wordexp_test.c
+++ b/lib/libc/tests/gen/wordexp_test.c
@@ -292,6 +292,31 @@ ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
ATF_REQUIRE(r == 0);
}
+ATF_TC_WITHOUT_HEAD(with_SIGCHILD_ignore_test);
+ATF_TC_BODY(with_SIGCHILD_ignore_test, tc)
+{
+ struct sigaction sa;
+ wordexp_t we;
+ int r;
+
+ /* With SIGCHLD set to ignore so that the kernel auto-reaps zombies. */
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("hello world", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+ sa.sa_handler = SIG_DFL;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+}
+
ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
{
@@ -350,6 +375,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
+ ATF_TP_ADD_TC(tp, with_SIGCHILD_ignore_test);
ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
diff --git a/lib/libc/tests/stdtime/Makefile b/lib/libc/tests/stdtime/Makefile
index c7a7f5b9436f..adb883cc5b9a 100644
--- a/lib/libc/tests/stdtime/Makefile
+++ b/lib/libc/tests/stdtime/Makefile
@@ -1,6 +1,9 @@
-.include <bsd.own.mk>
+.include <src.opts.mk>
ATF_TESTS_C+= strptime_test
+.if ${MK_DETECT_TZ_CHANGES} != "no"
+ATF_TESTS_C+= detect_tz_changes_test
+.endif
TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/}
diff --git a/lib/libc/tests/stdtime/detect_tz_changes_test.c b/lib/libc/tests/stdtime/detect_tz_changes_test.c
new file mode 100644
index 000000000000..9722546747fd
--- /dev/null
+++ b/lib/libc/tests/stdtime/detect_tz_changes_test.c
@@ -0,0 +1,281 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const time_t then = 1751328000; /* 2025-07-01 00:00:00 UTC */
+static const char *tz_change_interval_sym = "__tz_change_interval";
+static int *tz_change_interval_p;
+static const int tz_change_interval = 3;
+static int tz_change_timeout = 90;
+
+static bool debugging;
+
+static void
+debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (debugging) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ }
+}
+
+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";
+ ssize_t clen;
+ int zfd, sfd, dfd;
+
+ ATF_REQUIRE((zfd = open(zfn, O_DIRECTORY | O_SEARCH)) >= 0);
+ ATF_REQUIRE((sfd = openat(zfd, tzn, O_RDONLY)) >= 0);
+ ATF_REQUIRE((dfd = open(tfn, O_CREAT | O_TRUNC | O_WRONLY)) >= 0);
+ do {
+ clen = copy_file_range(sfd, NULL, dfd, NULL, SSIZE_MAX, 0);
+ ATF_REQUIRE_MSG(clen != -1, "failed to copy %s/%s: %m",
+ zfn, tzn);
+ } while (clen > 0);
+ ATF_CHECK_EQ(0, close(dfd));
+ ATF_CHECK_EQ(0, close(sfd));
+ ATF_CHECK_EQ(0, close(zfd));
+ ATF_REQUIRE_EQ(0, rename(tfn, dfn));
+ debug("time zone %s installed", tzn);
+}
+
+/*
+ * Test time zone change detection.
+ *
+ * The parent creates a chroot containing only /etc/localtime, initially
+ * set to UTC. It then forks a child which enters the chroot, repeatedly
+ * checks the current time zone, and prints it to stdout if it changes
+ * (including once on startup). Meanwhile, the parent waits for output
+ * from the child. Every time it receives a line of text from the child,
+ * it checks that it is as expected, then changes /etc/localtime within
+ * the chroot to the next case in the list. Once it reaches the end of
+ * the list, it closes a pipe to notify the child, which terminates.
+ *
+ * Note that ATF and / or Kyua may have set the timezone before the test
+ * case starts (even unintentionally). Therefore, we start the test only
+ * after we've received and discarded the first report from the child,
+ * which should come almost immediately on startup.
+ */
+ATF_TC(detect_tz_changes);
+ATF_TC_HEAD(detect_tz_changes, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test timezone change detection");
+ atf_tc_set_md_var(tc, "require.user", "root");
+ atf_tc_set_md_var(tc, "timeout", "600");
+}
+ATF_TC_BODY(detect_tz_changes, tc)
+{
+ static const struct tzcase {
+ const char *tzfn;
+ const char *expect;
+ } tzcases[] = {
+ /*
+ * A handful of time zones and the expected result of
+ * strftime("%z (%Z)", tm) when that time zone is active
+ * and tm represents a date in the summer of 2025.
+ */
+ { "America/Vancouver", "-0700 (PDT)" },
+ { "America/New_York", "-0400 (EDT)" },
+ { "Europe/London", "+0100 (BST)" },
+ { "Europe/Paris", "+0200 (CEST)" },
+ { "Asia/Kolkata", "+0530 (IST)" },
+ { "Asia/Tokyo", "+0900 (JST)" },
+ { "Australia/Canberra", "+1000 (AEST)" },
+ { "UTC", "+0000 (UTC)" },
+ { 0 },
+ };
+ char obuf[1024] = "";
+ char ebuf[1024] = "";
+ struct pollfd fds[3];
+ int opd[2], epd[2], spd[2];
+ time_t changed, now;
+ const struct tzcase *tzcase = NULL;
+ struct tm *tm;
+ size_t olen = 0, elen = 0;
+ ssize_t rlen;
+ long curoff = LONG_MIN;
+ pid_t pid;
+ int nfds, status;
+
+ /* speed up the test if possible */
+ tz_change_interval_p = dlsym(RTLD_SELF, tz_change_interval_sym);
+ if (tz_change_interval_p != NULL &&
+ *tz_change_interval_p > tz_change_interval) {
+ debug("reducing detection interval from %d to %d",
+ *tz_change_interval_p, tz_change_interval);
+ *tz_change_interval_p = tz_change_interval;
+ tz_change_timeout = tz_change_interval * 3;
+ }
+ /* prepare chroot */
+ ATF_REQUIRE_EQ(0, mkdir("root", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755));
+ change_tz("UTC");
+ time(&changed);
+ /* output, error, sync pipes */
+ if (pipe(opd) != 0 || pipe(epd) != 0 || pipe(spd) != 0)
+ atf_tc_fail("failed to pipe");
+ /* fork child */
+ if ((pid = fork()) < 0)
+ atf_tc_fail("failed to fork");
+ if (pid == 0) {
+ /* child */
+ dup2(opd[1], STDOUT_FILENO);
+ close(opd[0]);
+ close(opd[1]);
+ dup2(epd[1], STDERR_FILENO);
+ close(epd[0]);
+ close(epd[1]);
+ close(spd[0]);
+ unsetenv("TZ");
+ ATF_REQUIRE_EQ(0, chroot("root"));
+ ATF_REQUIRE_EQ(0, chdir("/"));
+ fds[0].fd = spd[1];
+ fds[0].events = POLLIN;
+ for (;;) {
+ ATF_REQUIRE(poll(fds, 1, 100) >= 0);
+ if (fds[0].revents & POLLHUP) {
+ /* parent closed sync pipe */
+ _exit(0);
+ }
+ ATF_REQUIRE((tm = localtime(&then)) != NULL);
+ if (tm->tm_gmtoff == curoff)
+ continue;
+ olen = strftime(obuf, sizeof(obuf), "%z (%Z)", tm);
+ ATF_REQUIRE(olen > 0);
+ fprintf(stdout, "%s\n", obuf);
+ fflush(stdout);
+ curoff = tm->tm_gmtoff;
+ }
+ _exit(2);
+ }
+ /* parent */
+ close(opd[1]);
+ close(epd[1]);
+ close(spd[1]);
+ /* receive output until child terminates */
+ fds[0].fd = opd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = epd[0];
+ fds[1].events = POLLIN;
+ fds[2].fd = spd[0];
+ fds[2].events = POLLIN;
+ nfds = 3;
+ for (;;) {
+ ATF_REQUIRE(poll(fds, 3, 1000) >= 0);
+ time(&now);
+ if (fds[0].revents & POLLIN && olen < sizeof(obuf)) {
+ rlen = read(opd[0], obuf + olen, sizeof(obuf) - olen);
+ ATF_REQUIRE(rlen >= 0);
+ olen += rlen;
+ }
+ if (olen > 0) {
+ ATF_REQUIRE_EQ('\n', obuf[olen - 1]);
+ obuf[--olen] = '\0';
+ /* tzcase will be NULL at first */
+ if (tzcase != NULL) {
+ debug("%s", obuf);
+ ATF_REQUIRE_STREQ(tzcase->expect, obuf);
+ debug("change to %s detected after %d s",
+ tzcase->tzfn, (int)(now - changed));
+ if (tz_change_interval_p != NULL) {
+ ATF_CHECK((int)(now - changed) >=
+ *tz_change_interval_p - 1);
+ ATF_CHECK((int)(now - changed) <=
+ *tz_change_interval_p + 1);
+ }
+ }
+ olen = 0;
+ /* first / next test case */
+ if (tzcase == NULL)
+ tzcase = tzcases;
+ else
+ tzcase++;
+ if (tzcase->tzfn == NULL) {
+ /* test is over */
+ break;
+ }
+ change_tz(tzcase->tzfn);
+ changed = now;
+ }
+ if (fds[1].revents & POLLIN && elen < sizeof(ebuf)) {
+ rlen = read(epd[0], ebuf + elen, sizeof(ebuf) - elen);
+ ATF_REQUIRE(rlen >= 0);
+ elen += rlen;
+ }
+ if (elen > 0) {
+ ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr));
+ elen = 0;
+ }
+ if (nfds > 2 && fds[2].revents & POLLHUP) {
+ /* child closed sync pipe */
+ break;
+ }
+ /*
+ * The timeout for this test case is set to 10 minutes,
+ * because it can take that long to run with the default
+ * 61-second interval. However, each individual tzcase
+ * entry should not take much longer than the detection
+ * interval to test, so we can detect a problem long
+ * before Kyua terminates us.
+ */
+ if ((now - changed) > tz_change_timeout) {
+ close(spd[0]);
+ if (tz_change_interval_p == NULL &&
+ tzcase == tzcases) {
+ /*
+ * The most likely explanation in this
+ * case is that libc was built without
+ * time zone change detection.
+ */
+ atf_tc_skip("time zone change detection "
+ "does not appear to be enabled");
+ }
+ atf_tc_fail("timed out waiting for change to %s "
+ "to be detected", tzcase->tzfn);
+ }
+ }
+ close(opd[0]);
+ close(epd[0]);
+ close(spd[0]); /* this will wake up and terminate the child */
+ if (olen > 0)
+ ATF_REQUIRE_EQ(olen, fwrite(obuf, 1, olen, stdout));
+ if (elen > 0)
+ ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr));
+ ATF_REQUIRE_EQ(pid, waitpid(pid, &status, 0));
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(0, WEXITSTATUS(status));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ debugging = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
+ isatty(STDERR_FILENO);
+ ATF_TP_ADD_TC(tp, detect_tz_changes);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile
index 89d341ff400a..88f8191a16eb 100644
--- a/lib/libc/tests/sys/Makefile
+++ b/lib/libc/tests/sys/Makefile
@@ -7,11 +7,11 @@ ATF_TESTS_C+= brk_test
.endif
ATF_TESTS_C+= cpuset_test
ATF_TESTS_C+= errno_test
+ATF_TESTS_C+= swapcontext_test
ATF_TESTS_C+= queue_test
ATF_TESTS_C+= sendfile_test
-# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg,
-# swapcontext
+# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg
NETBSD_ATF_TESTS_C+= access_test
NETBSD_ATF_TESTS_C+= bind_test
NETBSD_ATF_TESTS_C+= chroot_test
diff --git a/lib/libc/tests/sys/swapcontext_test.c b/lib/libc/tests/sys/swapcontext_test.c
new file mode 100644
index 000000000000..f341a746e515
--- /dev/null
+++ b/lib/libc/tests/sys/swapcontext_test.c
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2025 Raptor Computing Systems, LLC
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ucontext.h>
+#include <errno.h>
+
+#include <atf-c.h>
+
+#define STACK_SIZE (64ull << 10)
+
+static volatile int callback_reached = 0;
+
+static ucontext_t uctx_save, uctx_switch;
+
+static void swapcontext_callback()
+{
+ // Increment callback reached variable
+ // If this is called multiple times, we will fail the test
+ // If this is not called at all, we will fail the test
+ callback_reached++;
+}
+
+ATF_TC(swapcontext_basic);
+ATF_TC_HEAD(swapcontext_basic, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify basic functionality of swapcontext");
+}
+
+ATF_TC_BODY(swapcontext_basic, tc)
+{
+ char *stack;
+ int res;
+
+ stack = malloc(STACK_SIZE);
+ ATF_REQUIRE_MSG(stack != NULL, "malloc failed: %s", strerror(errno));
+ res = getcontext(&uctx_switch);
+ ATF_REQUIRE_MSG(res == 0, "getcontext failed: %s", strerror(errno));
+
+ uctx_switch.uc_stack.ss_sp = stack;
+ uctx_switch.uc_stack.ss_size = STACK_SIZE;
+ uctx_switch.uc_link = &uctx_save;
+ makecontext(&uctx_switch, swapcontext_callback, 0);
+
+ res = swapcontext(&uctx_save, &uctx_switch);
+
+ ATF_REQUIRE_MSG(res == 0, "swapcontext failed: %s", strerror(errno));
+ ATF_REQUIRE_MSG(callback_reached == 1,
+ "callback failed, reached %d times", callback_reached);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, swapcontext_basic);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/libcasper/services/cap_dns/tests/dns_test.c b/lib/libcasper/services/cap_dns/tests/dns_test.c
index 76534bbbebad..56d867e474f5 100644
--- a/lib/libcasper/services/cap_dns/tests/dns_test.c
+++ b/lib/libcasper/services/cap_dns/tests/dns_test.c
@@ -198,18 +198,17 @@ hostent_compare(const struct hostent *hp0, const struct hostent *hp1)
static void
runtest(cap_channel_t *capdns, unsigned int expected)
{
- unsigned int result, failure;
+ unsigned int result;
struct addrinfo *ais, *aic, hints, *hintsp;
struct hostent *hps, *hpc;
struct in_addr ip4;
struct in6_addr ip6;
int caperr, syserr;
- failure = result = 0;
+ result = 0;
hps = gethostbyname("example.com");
if (hps == NULL) {
- failure |= GETHOSTBYNAME;
fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
} else {
hpc = cap_gethostbyname(capdns, "example.com");
@@ -219,7 +218,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hps = gethostbyname2("example.com", AF_INET);
if (hps == NULL) {
- failure |= GETHOSTBYNAME2_AF_INET;
fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
} else {
hpc = cap_gethostbyname2(capdns, "example.com", AF_INET);
@@ -229,7 +227,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hps = gethostbyname2("example.com", AF_INET6);
if (hps == NULL) {
- failure |= GETHOSTBYNAME2_AF_INET6;
fprintf(stderr, "Unable to resolve %s IPv6.\n", "example.com");
} else {
hpc = cap_gethostbyname2(capdns, "example.com", AF_INET6);
@@ -250,7 +247,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_UNSPEC;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -268,7 +264,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hints.ai_family = AF_INET;
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_INET;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -286,7 +281,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hints.ai_family = AF_INET6;
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_INET6;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -308,7 +302,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
inet_pton(AF_INET, GOOGLE_DNS_IPV4, &ip4);
hps = gethostbyaddr(&ip4, sizeof(ip4), AF_INET);
if (hps == NULL) {
- failure |= GETHOSTBYADDR_AF_INET;
fprintf(stderr, "Unable to resolve %s.\n", GOOGLE_DNS_IPV4);
} else {
hpc = cap_gethostbyaddr(capdns, &ip4, sizeof(ip4), AF_INET);
@@ -319,7 +312,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
inet_pton(AF_INET6, GOOGLE_DNS_IPV6, &ip6);
hps = gethostbyaddr(&ip6, sizeof(ip6), AF_INET6);
if (hps == NULL) {
- failure |= GETHOSTBYADDR_AF_INET6;
fprintf(stderr, "Unable to resolve %s.\n", GOOGLE_DNS_IPV6);
} else {
hpc = cap_gethostbyaddr(capdns, &ip6, sizeof(ip6), AF_INET6);
@@ -329,21 +321,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
}
}
- /*
- * If we had any failures, make sure that all lookups failed. If some
- * succeeded and some failed, there's a problem with the test or the DNS
- * and we should not fail silently.
- */
- if (failure != 0) {
- ATF_REQUIRE_MSG(failure == (GETHOSTBYNAME |
- GETHOSTBYNAME2_AF_INET | GETHOSTBYNAME2_AF_INET6 |
- GETADDRINFO_AF_UNSPEC | GETADDRINFO_AF_INET |
- GETADDRINFO_AF_INET6 |
- GETHOSTBYADDR_AF_INET | GETHOSTBYADDR_AF_INET6),
- "expected all tests to fail, got 0x%x", failure);
- atf_tc_skip(
- "no name lookups succeeded, tests require Internet access");
- }
ATF_REQUIRE_MSG(result == expected,
"expected 0x%x, got 0x%x", expected, result);
}
@@ -367,6 +344,7 @@ cap_dns_init(void)
ATF_TC(dns_no_limits);
ATF_TC_HEAD(dns_no_limits, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_no_limits, tc)
{
@@ -386,6 +364,7 @@ ATF_TC_BODY(dns_no_limits, tc)
ATF_TC(dns_all_limits);
ATF_TC_HEAD(dns_all_limits, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_all_limits, tc)
{
@@ -417,6 +396,7 @@ ATF_TC_BODY(dns_all_limits, tc)
ATF_TC(dns_name_limit);
ATF_TC_HEAD(dns_name_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_limit, tc)
{
@@ -448,6 +428,7 @@ ATF_TC_BODY(dns_name_limit, tc)
ATF_TC(dns_addr_limit);
ATF_TC_HEAD(dns_addr_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_limit, tc)
{
@@ -478,6 +459,7 @@ ATF_TC_BODY(dns_addr_limit, tc)
ATF_TC(dns_inet_limit);
ATF_TC_HEAD(dns_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_inet_limit, tc)
{
@@ -509,6 +491,7 @@ ATF_TC_BODY(dns_inet_limit, tc)
ATF_TC(dns_inet6_limit);
ATF_TC_HEAD(dns_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_inet6_limit, tc)
{
@@ -540,6 +523,7 @@ ATF_TC_BODY(dns_inet6_limit, tc)
ATF_TC(dns_name_inet_limit);
ATF_TC_HEAD(dns_name_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_inet_limit, tc)
{
@@ -581,6 +565,7 @@ ATF_TC_BODY(dns_name_inet_limit, tc)
ATF_TC(dns_name_inet6_limit);
ATF_TC_HEAD(dns_name_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_inet6_limit, tc)
{
@@ -622,6 +607,7 @@ ATF_TC_BODY(dns_name_inet6_limit, tc)
ATF_TC(dns_addr_inet_limit);
ATF_TC_HEAD(dns_addr_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_inet_limit, tc)
{
@@ -662,6 +648,7 @@ ATF_TC_BODY(dns_addr_inet_limit, tc)
ATF_TC(dns_addr_inet6_limit);
ATF_TC_HEAD(dns_addr_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_inet6_limit, tc)
{
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
index 0d85ed468284..786d5647d993 100644
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -277,13 +277,16 @@ conn_t *
fetch_reopen(int sd)
{
conn_t *conn;
+ int flags;
int opt = 1;
/* allocate and fill connection structure */
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return (NULL);
- fcntl(sd, F_SETFD, FD_CLOEXEC);
- setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt);
+ flags = fcntl(sd, F_GETFD);
+ if (flags != -1 && (flags & FD_CLOEXEC) == 0)
+ (void)fcntl(sd, F_SETFD, flags | FD_CLOEXEC);
+ (void)setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
conn->sd = sd;
++conn->ref;
return (conn);
diff --git a/lib/libnvmf/libnvmf.h b/lib/libnvmf/libnvmf.h
index 9840e190a24f..7cdd7e433455 100644
--- a/lib/libnvmf/libnvmf.h
+++ b/lib/libnvmf/libnvmf.h
@@ -342,7 +342,8 @@ int nvmf_host_request_queues(struct nvmf_qpair *qp, u_int requested,
*/
int nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Disconnect an active host association previously handed off to the
@@ -370,7 +371,8 @@ int nvmf_reconnect_params(int fd, nvlist_t **nvlp);
*/
int nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Fetch connection status from an existing kernel host.
diff --git a/lib/libnvmf/nvmf_host.c b/lib/libnvmf/nvmf_host.c
index 89cdd5c6bb70..3266f8898296 100644
--- a/lib/libnvmf/nvmf_host.c
+++ b/lib/libnvmf/nvmf_host.c
@@ -792,7 +792,8 @@ static int
prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
const struct nvme_discovery_log_entry *dle, const char *hostnqn,
struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
const struct nvmf_association *na = admin_qp->nq_association;
nvlist_t *nvl, *nvl_qp, *nvl_rparams;
@@ -820,6 +821,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvlist_add_string(nvl_rparams, "hostnqn", hostnqn);
nvlist_add_number(nvl_rparams, "num_io_queues", num_queues);
nvlist_add_number(nvl_rparams, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl_rparams, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl_rparams, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_add_number(nvl_rparams, "io_qsize", io_queues[0]->nq_qsize);
nvlist_add_bool(nvl_rparams, "sq_flow_control",
na->na_params.sq_flow_control);
@@ -842,6 +846,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvl = nvlist_create(0);
nvlist_add_number(nvl, "trtype", na->na_trtype);
nvlist_add_number(nvl, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_move_nvlist(nvl, "rparams", nvl_rparams);
/* First, the admin queue. */
@@ -872,7 +879,8 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
int
nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
@@ -885,7 +893,8 @@ nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
}
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
@@ -981,14 +990,16 @@ nvmf_reconnect_params(int fd, nvlist_t **nvlp)
int
nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
int error;
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
diff --git a/lib/libsecureboot/h/libsecureboot.h b/lib/libsecureboot/h/libsecureboot.h
index 017558536825..d32df9594332 100644
--- a/lib/libsecureboot/h/libsecureboot.h
+++ b/lib/libsecureboot/h/libsecureboot.h
@@ -29,6 +29,7 @@
#include <sys/param.h>
#ifdef _STANDALONE
+#define _DEBUG_LEVEL_VAR DebugVe
#include <stand.h>
#else
#include <sys/types.h>
diff --git a/lib/libsys/fcntl.2 b/lib/libsys/fcntl.2
index 3cf8adc29f88..d67c38cfbc6c 100644
--- a/lib/libsys/fcntl.2
+++ b/lib/libsys/fcntl.2
@@ -577,7 +577,7 @@ A new file descriptor.
A file descriptor equal to
.Fa arg .
.It Dv F_GETFD
-Value of flag (only the low-order bit is defined).
+Value of flags.
.It Dv F_GETFL
Value of flags.
.It Dv F_GETOWN
diff --git a/lib/libsys/fhopen.2 b/lib/libsys/fhopen.2
index aba53f1dd907..b281ac3d8949 100644
--- a/lib/libsys/fhopen.2
+++ b/lib/libsys/fhopen.2
@@ -31,7 +31,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd April 6, 2025
+.Dd July 20, 2025
.Dt FHOPEN 2
.Os
.Sh NAME
@@ -140,7 +140,7 @@ is no longer valid.
.Xr fstatfs 2 ,
.Xr getfh 2 ,
.Xr open 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn fhopen ,
diff --git a/lib/libsys/getdirentries.2 b/lib/libsys/getdirentries.2
index 0e5840ce25cd..202ae133f548 100644
--- a/lib/libsys/getdirentries.2
+++ b/lib/libsys/getdirentries.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 5, 2023
+.Dd July 8, 2025
.Dt GETDIRENTRIES 2
.Os
.Sh NAME
@@ -178,9 +178,7 @@ or non-NULL
.Fa basep
point outside the allocated address space.
.It Bq Er EINVAL
-The file referenced by
-.Fa fd
-is not a directory, or
+The value of
.Fa nbytes
is too small for returning a directory entry or block of entries,
or the current position pointer is invalid.
@@ -192,6 +190,10 @@ error occurred while reading from or writing to the file system.
Corrupted data was detected while reading from the file system.
.It Bq Er ENOENT
Directory unlinked but still open.
+.It Bq Er ENOTDIR
+The file referenced by
+.Fa fd
+is not a directory.
.El
.Sh SEE ALSO
.Xr lseek 2 ,
diff --git a/lib/libsys/statfs.2 b/lib/libsys/statfs.2
index 49e8b5120558..ab65def11ebb 100644
--- a/lib/libsys/statfs.2
+++ b/lib/libsys/statfs.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 7, 2025
+.Dd July 20, 2025
.Dt STATFS 2
.Os
.Sh NAME
@@ -127,7 +127,7 @@ Mandatory Access Control (MAC) support for individual objects
.Xr mac 4 ) .
.It Dv MNT_NAMEDATTR
The file system supports named attributes as described in
-.Xr named_attribute 9 .
+.Xr named_attribute 7 .
.It Dv MNT_NFS4ACLS
ACLs in NFSv4 variant are supported.
.It Dv MNT_NOATIME
@@ -264,7 +264,7 @@ each file or directory name or disk label
.Sh SEE ALSO
.Xr fhstatfs 2 ,
.Xr getfsstat 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn statfs
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
index 1c8dde03367b..3a5353a32dc3 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -136,7 +136,6 @@ FBSDprivate_1.0 {
__pthread_mutex_lock;
__pthread_mutex_timedlock;
__pthread_mutex_trylock;
- __pthread_distribute_static_tls;
_pthread_atfork;
_pthread_barrier_destroy;
_pthread_barrier_init;
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
index 820766f6f5e0..cbf16179f619 100644
--- a/lib/libthr/thread/thr_list.c
+++ b/lib/libthr/thread/thr_list.c
@@ -363,41 +363,3 @@ _thr_find_thread(struct pthread *curthread, struct pthread *thread,
THREAD_LIST_UNLOCK(curthread);
return (ret);
}
-
-static void
-thr_distribute_static_tls(char *tlsbase, void *src, size_t len,
- size_t total_len)
-{
-
- memcpy(tlsbase, src, len);
- memset(tlsbase + len, 0, total_len - len);
-}
-
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- struct pthread *curthread, *thrd;
- char *tlsbase;
-
- if (!_thr_is_inited()) {
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)_tcb_get() + offset;
-#else
- tlsbase = (char *)_tcb_get() - offset;
-#endif
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- return;
- }
- curthread = _get_curthread();
- THREAD_LIST_RDLOCK(curthread);
- TAILQ_FOREACH(thrd, &_thread_list, tle) {
-#ifdef TLS_VARIANT_I
- tlsbase = (char *)thrd->tcb + offset;
-#else
- tlsbase = (char *)thrd->tcb - offset;
-#endif
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- }
- THREAD_LIST_UNLOCK(curthread);
-}
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index bca890829057..d7b889930365 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -986,8 +986,6 @@ void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_stack_fix_protection(struct pthread *thrd);
-void __pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len);
int *__error_threaded(void) __hidden;
void __thr_interpose_libc(void) __hidden;
diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3
index a9a99f307a86..9dc752f0fd7b 100644
--- a/lib/libusb/libusb.3
+++ b/lib/libusb/libusb.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 12, 2025
+.Dd July 9, 2025
.Dt LIBUSB 3
.Os
.Sh NAME
@@ -106,6 +106,19 @@ Get the ASCII representation of the error given by the
argument.
This function does not return NULL.
.Pp
+.Ft int
+.Fn libusb_setlocale "const char *locale"
+Set locale for the error message when using
+.Fn libusb_strerror
+to
+.Ft locale .
+Note other
+.Nm
+implementations only support the first two bytes, that means
+.Ql en-US
+is equivalent to
+.Ql en-CA .
+.Pp
.Ft const char *
.Fn libusb_error_name "int code"
Get the ASCII representation of the error enum given by the
@@ -353,6 +366,23 @@ argument is non-zero the feature is enabled.
Else disabled.
Returns 0 on success and a LIBUSB_ERROR code on
failure.
+.Pp
+.Ft unsigned char *
+.Fn libusb_dev_mem_alloc "libusb_device_handle *devh"
+This function attempts to allocate a DMA memory block from the given
+.Fa devh
+so that we can enjoy the zero-copy transfer from kernel.
+This function is provided for compatibility and is currently unimplemented and always returns NULL.
+.Pp
+.Ft int
+.Fn libusb_dev_mem_free "libusb_device_handle *devh" "unsigned char *buffer" "size_t size"
+This function frees the DMA memory in
+.Fa devh
+from the given
+.Fa buffer
+with
+.Fa size .
+This function is unimplemented and always returns LIBUSB_ERROR_NOT_SUPPORTED.
.Sh USB DESCRIPTORS
.Ft int
.Fn libusb_get_device_descriptor "libusb_device *dev" "libusb_device_descriptor *desc"
@@ -762,6 +792,17 @@ argument can be either of LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED or LIBUSB_HOTPLUG_
.Ft void
.Fn libusb_hotplug_deregister_callback "libusb_context *ctx" "libusb_hotplug_callback_handle handle"
This function unregisters a hotplug filter.
+.Pp
+.Ft void
+.Fn libusb_free_pollfds "const struct libusb_pollfd **pollfds"
+This function releases the memory storage in
+.Fa pollfds ,
+and is safe to call when the argument is NULL.
+.Pp void *
+.Fn libusb_hotplug_get_user_data "struct libusb_context *ctx" "libusb_hotplug_callback_handle callback_handle"
+This function returns the user data from the opaque
+.Fa callback_handle ,
+or returns NULL if no matching handle is found.
.Sh LIBUSB VERSION 0.1 COMPATIBILITY
The library is also compliant with LibUSB version 0.1.12.
.Pp
diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h
index 0aad29aa4ecc..1803ff637738 100644
--- a/lib/libusb/libusb.h
+++ b/lib/libusb/libusb.h
@@ -122,6 +122,7 @@ enum libusb_transfer_type {
LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
LIBUSB_TRANSFER_TYPE_BULK = 2,
LIBUSB_TRANSFER_TYPE_INTERRUPT = 3,
+ LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4,
};
enum libusb_standard_request {
@@ -210,6 +211,8 @@ enum libusb_error {
LIBUSB_ERROR_OTHER = -99,
};
+#define LIBUSB_ERROR_COUNT 14
+
enum libusb_speed {
LIBUSB_SPEED_UNKNOWN = 0,
LIBUSB_SPEED_LOW = 1,
@@ -243,17 +246,6 @@ enum libusb_log_level {
LIBUSB_LOG_LEVEL_DEBUG
};
-/* XXX */
-/* libusb_set_debug should take parameters from libusb_log_level
- * above according to
- * https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html
- */
-enum libusb_debug_level {
- LIBUSB_DEBUG_NO=0,
- LIBUSB_DEBUG_FUNCTION=1,
- LIBUSB_DEBUG_TRANSFER=2,
-};
-
#define LIBUSB_HOTPLUG_MATCH_ANY -1
typedef enum {
@@ -418,7 +410,10 @@ typedef struct libusb_bos_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
- uint8_t bNumDeviceCapabilities;
+#ifndef bNumDeviceCapabilities
+#define bNumDeviceCapabilities bNumDeviceCaps
+#endif
+ uint8_t bNumDeviceCaps;
struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap;
struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap;
struct libusb_bos_dev_capability_descriptor **dev_capability;
@@ -483,6 +478,7 @@ int libusb_init(libusb_context ** context);
int libusb_init_context(libusb_context **, const struct libusb_init_option [], int num_options);
void libusb_exit(struct libusb_context *ctx);
int libusb_has_capability(uint32_t capability);
+int libusb_setlocale(const char *locale);
/* Device handling and enumeration */
@@ -518,6 +514,9 @@ int libusb_detach_kernel_driver(libusb_device_handle * devh, int interface);
int libusb_attach_kernel_driver(libusb_device_handle * devh, int interface);
int libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable);
int libusb_set_interface_alt_setting(libusb_device_handle * devh, int interface_number, int alternate_setting);
+unsigned char *libusb_dev_mem_alloc(libusb_device_handle *devh);
+int libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer,
+ size_t size);
/* USB Descriptors */
@@ -578,7 +577,8 @@ int libusb_handle_events(libusb_context * ctx);
int libusb_handle_events_locked(libusb_context * ctx, struct timeval *tv);
int libusb_get_next_timeout(libusb_context * ctx, struct timeval *tv);
void libusb_set_pollfd_notifiers(libusb_context * ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data);
-const struct libusb_pollfd **libusb_get_pollfds(libusb_context * ctx);
+const struct libusb_pollfd **libusb_get_pollfds(libusb_context *ctx);
+void libusb_free_pollfds(const struct libusb_pollfd **pollfds);
/* Synchronous device I/O */
@@ -598,6 +598,8 @@ typedef int (*libusb_hotplug_callback_fn)(libusb_context *ctx,
int libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *handle);
void libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle handle);
+void *libusb_hotplug_get_user_data(struct libusb_context *ctx,
+ libusb_hotplug_callback_handle callback_handle);
/* Streams support */
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c
index 3e81f234a735..5c116b39ea17 100644
--- a/lib/libusb/libusb10.c
+++ b/lib/libusb/libusb10.c
@@ -4,6 +4,7 @@
* Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
* Copyright (c) 2009-2023 Hans Petter Selasky
* Copyright (c) 2024 Aymeric Wibo
+ * Copyright (c) 2025 ShengYi Hung
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,10 +32,12 @@
#include LIBUSB_GLOBAL_INCLUDE_FILE
#else
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -48,6 +51,7 @@
#endif
#define libusb_device_handle libusb20_device
+#define LIBUSB_LOG_BUFFER_SIZE 1024
#include "libusb20.h"
#include "libusb20_desc.h"
@@ -82,6 +86,52 @@ static const struct libusb_version libusb_version = {
.describe = "https://www.freebsd.org"
};
+static const struct libusb_language_context libusb_language_ctx[] = {
+ {
+ .lang_name = "en",
+ .err_strs = {
+ [-LIBUSB_SUCCESS] = "Success",
+ [-LIBUSB_ERROR_IO] = "I/O error",
+ [-LIBUSB_ERROR_INVALID_PARAM] = "Invalid parameter",
+ [-LIBUSB_ERROR_ACCESS] = "Permissions error",
+ [-LIBUSB_ERROR_NO_DEVICE] = "No device",
+ [-LIBUSB_ERROR_NOT_FOUND] = "Not found",
+ [-LIBUSB_ERROR_BUSY] = "Device busy",
+ [-LIBUSB_ERROR_TIMEOUT] = "Timeout",
+ [-LIBUSB_ERROR_OVERFLOW] = "Overflow",
+ [-LIBUSB_ERROR_PIPE] = "Pipe error",
+ [-LIBUSB_ERROR_INTERRUPTED] = "Interrupted",
+ [-LIBUSB_ERROR_NO_MEM] = "Out of memory",
+ [-LIBUSB_ERROR_NOT_SUPPORTED] ="Not supported",
+ [LIBUSB_ERROR_COUNT - 1] = "Other error",
+ [LIBUSB_ERROR_COUNT] = "Unknown error",
+ }
+ },
+ {
+ .lang_name = "zh",
+ .err_strs = {
+ [-LIBUSB_SUCCESS] = "成功",
+ [-LIBUSB_ERROR_IO] = "I/O 錯誤",
+ [-LIBUSB_ERROR_INVALID_PARAM] = "不合法的參數",
+ [-LIBUSB_ERROR_ACCESS] = "權限錯誤",
+ [-LIBUSB_ERROR_NO_DEVICE] = "裝置不存在",
+ [-LIBUSB_ERROR_NOT_FOUND] = "不存在",
+ [-LIBUSB_ERROR_BUSY] = "裝置忙碌中",
+ [-LIBUSB_ERROR_TIMEOUT] = "逾時",
+ [-LIBUSB_ERROR_OVERFLOW] = "溢位",
+ [-LIBUSB_ERROR_PIPE] = "管道錯誤",
+ [-LIBUSB_ERROR_INTERRUPTED] = "被中斷",
+ [-LIBUSB_ERROR_NO_MEM] = "記憶體不足",
+ [-LIBUSB_ERROR_NOT_SUPPORTED] ="不支援",
+ [LIBUSB_ERROR_COUNT - 1] = "其他錯誤",
+ [LIBUSB_ERROR_COUNT] = "未知錯誤",
+ }
+ },
+};
+
+static const struct libusb_language_context *default_language_context =
+ &libusb_language_ctx[0];
+
const struct libusb_version *
libusb_get_version(void)
{
@@ -128,7 +178,7 @@ libusb_interrupt_event_handler(libusb_context *ctx)
err = eventfd_write(ctx->event, 1);
if (err < 0) {
/* ignore error, if any */
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "Waking up event loop failed!");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_ERROR, "Waking up event loop failed!");
}
}
@@ -253,7 +303,7 @@ libusb_init_context(libusb_context **context,
if (context)
*context = ctx;
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_INFO, "libusb_init complete");
signal(SIGPIPE, SIG_IGN);
@@ -625,7 +675,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
if (ctx == NULL)
return (NULL); /* be NULL safe */
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid enter");
if ((i = libusb_get_device_list(ctx, &devs)) < 0)
return (NULL);
@@ -649,7 +699,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
}
libusb_free_device_list(devs, 1);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid leave");
return (pdev);
}
@@ -1480,6 +1530,7 @@ found:
libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
break;
case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
break;
@@ -1536,7 +1587,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer)
dev = libusb_get_device(uxfer->dev_handle);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer enter");
sxfer = (struct libusb_super_transfer *)(
(uint8_t *)uxfer - sizeof(*sxfer));
@@ -1571,7 +1622,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer)
CTX_UNLOCK(dev->ctx);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer leave %d", err);
return (err);
}
@@ -1600,7 +1651,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer)
dev = libusb_get_device(devh);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer enter");
sxfer = (struct libusb_super_transfer *)(
(uint8_t *)uxfer - sizeof(*sxfer));
@@ -1661,7 +1712,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer)
CTX_UNLOCK(dev->ctx);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer leave");
return (retval);
}
@@ -1726,38 +1777,26 @@ libusb_le16_to_cpu(uint16_t x)
const char *
libusb_strerror(int code)
{
- switch (code) {
- case LIBUSB_SUCCESS:
- return ("Success");
- case LIBUSB_ERROR_IO:
- return ("I/O error");
- case LIBUSB_ERROR_INVALID_PARAM:
- return ("Invalid parameter");
- case LIBUSB_ERROR_ACCESS:
- return ("Permissions error");
- case LIBUSB_ERROR_NO_DEVICE:
- return ("No device");
- case LIBUSB_ERROR_NOT_FOUND:
- return ("Not found");
- case LIBUSB_ERROR_BUSY:
- return ("Device busy");
- case LIBUSB_ERROR_TIMEOUT:
- return ("Timeout");
- case LIBUSB_ERROR_OVERFLOW:
- return ("Overflow");
- case LIBUSB_ERROR_PIPE:
- return ("Pipe error");
- case LIBUSB_ERROR_INTERRUPTED:
- return ("Interrupted");
- case LIBUSB_ERROR_NO_MEM:
- return ("Out of memory");
- case LIBUSB_ERROR_NOT_SUPPORTED:
- return ("Not supported");
- case LIBUSB_ERROR_OTHER:
- return ("Other error");
- default:
- return ("Unknown error");
- }
+ int entry = -code;
+
+ if (code == LIBUSB_ERROR_OTHER)
+ entry = LIBUSB_ERROR_COUNT - 1;
+ /*
+ * The libusb upstream considers all code out of range a
+ * LIBUSB_ERROR_OTHER. In FreeBSD, it is a special unknown error. We
+ * preserve the FreeBSD implementation as I think it make sense.
+ */
+ if (entry < 0 || entry >= LIBUSB_ERROR_COUNT)
+ entry = LIBUSB_ERROR_COUNT;
+
+ /*
+ * Fall back to English one as the translation may be unimplemented
+ * when adding new error code.
+ */
+ if (default_language_context->err_strs[entry] == NULL)
+ return (libusb_language_ctx[0].err_strs[entry]);
+
+ return (default_language_context->err_strs[entry]);
}
const char *
@@ -1811,3 +1850,71 @@ libusb_has_capability(uint32_t capability)
return (0);
}
}
+
+void
+libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level,
+ const char *fmt, ...)
+{
+ static const char *log_prefix[5] = {
+ [LIBUSB_LOG_LEVEL_ERROR] = "LIBUSB_ERROR",
+ [LIBUSB_LOG_LEVEL_WARNING] = "LIBUSB_WARN",
+ [LIBUSB_LOG_LEVEL_INFO] = "LIBUSB_INFO",
+ [LIBUSB_LOG_LEVEL_DEBUG] = "LIBUSB_DEBUG",
+ };
+
+ char buffer[LIBUSB_LOG_BUFFER_SIZE];
+ char new_fmt[LIBUSB_LOG_BUFFER_SIZE];
+ va_list args;
+
+ ctx = GET_CONTEXT(ctx);
+
+ if (ctx->debug < level)
+ return;
+
+ va_start(args, fmt);
+
+ snprintf(new_fmt, sizeof(new_fmt), "%s: %s\n", log_prefix[level], fmt);
+ vsnprintf(buffer, sizeof(buffer), new_fmt, args);
+ fputs(buffer, stdout);
+
+ va_end(args);
+}
+
+/*
+ * Upstream code actually recognizes the first two characters to identify a
+ * language. We do so to provide API compatibility with setlocale.
+ */
+int
+libusb_setlocale(const char *locale)
+{
+ size_t idx;
+ const char *lang;
+
+ if (locale == NULL || strlen(locale) < 2 ||
+ (locale[2] != '\0' && strchr("-_.", locale[2]) == NULL))
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ for (idx = 0; idx < nitems(libusb_language_ctx); ++idx) {
+ lang = libusb_language_ctx[idx].lang_name;
+ if (tolower(locale[0]) == lang[0] &&
+ tolower(locale[1]) == lang[1]) {
+ default_language_context = &libusb_language_ctx[idx];
+ return (LIBUSB_SUCCESS);
+ }
+ }
+
+ return (LIBUSB_ERROR_INVALID_PARAM);
+}
+
+unsigned char *
+libusb_dev_mem_alloc(libusb_device_handle *devh)
+{
+ return (NULL);
+}
+
+int
+libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer,
+ size_t size)
+{
+ return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h
index 70b5525df537..eced364ef857 100644
--- a/lib/libusb/libusb10.h
+++ b/lib/libusb/libusb10.h
@@ -29,6 +29,7 @@
#define __LIBUSB10_H__
#ifndef LIBUSB_GLOBAL_INCLUDE_FILE
+#include <sys/cdefs.h>
#include <sys/queue.h>
#include <netlink/netlink.h>
#include <netlink/netlink_generic.h>
@@ -46,24 +47,11 @@
#define HOTPLUG_LOCK(ctx) pthread_mutex_lock(&(ctx)->hotplug_lock)
#define HOTPLUG_UNLOCK(ctx) pthread_mutex_unlock(&(ctx)->hotplug_lock)
-#define DPRINTF(ctx, dbg, format, ...) do { \
- switch (dbg) { \
- case LIBUSB_DEBUG_FUNCTION: \
- if ((ctx)->debug & LIBUSB_DEBUG_FUNCTION) { \
- printf("LIBUSB_FUNCTION: " \
- format "\n", ## __VA_ARGS__); \
- } \
- break; \
- case LIBUSB_DEBUG_TRANSFER: \
- if ((ctx)->debug & LIBUSB_DEBUG_TRANSFER) { \
- printf("LIBUSB_TRANSFER: " \
- format "\n", ## __VA_ARGS__); \
- } \
- break; \
- default: \
- break; \
- } \
-} while (0)
+void libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level,
+ const char *fmt, ...) __printflike(3, 4);
+
+#define DPRINTF(ctx, dbg, format, ...) \
+ libusb_log_va_args(ctx, dbg, format, ##__VA_ARGS__)
/* internal structures */
@@ -151,6 +139,12 @@ struct libusb_device {
struct libusb20_device *os_priv;
};
+struct libusb_language_context {
+ const char *lang_name;
+ /* All error Plus 1 UNKNOWN */
+ const char *err_strs[LIBUSB_ERROR_COUNT + 1];
+};
+
extern struct libusb_context *usbi_default_context;
void libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd, struct libusb20_device *pdev, int fd, short events);
diff --git a/lib/libusb/libusb10_desc.c b/lib/libusb/libusb10_desc.c
index 3e36009cbb3a..5f4c46740688 100644
--- a/lib/libusb/libusb10_desc.c
+++ b/lib/libusb/libusb10_desc.c
@@ -470,10 +470,11 @@ libusb_parse_bos_descriptor(const void *buf, int len,
ptr->bDescriptorType = dtype;
ptr->wTotalLength = ((const uint8_t *)buf)[2] |
(((const uint8_t *)buf)[3] << 8);
- ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4];
+ ptr->bNumDeviceCaps = ((const uint8_t *)buf)[4];
ptr->usb_2_0_ext_cap = NULL;
ptr->ss_usb_cap = NULL;
- ptr->dev_capability = calloc(ptr->bNumDeviceCapabilities, sizeof(void *));
+ ptr->dev_capability = calloc(ptr->bNumDeviceCaps,
+ sizeof(void *));
if (ptr->dev_capability == NULL) {
free(ptr);
return (LIBUSB_ERROR_NO_MEM);
@@ -485,7 +486,7 @@ libusb_parse_bos_descriptor(const void *buf, int len,
if (dlen >= 3 &&
ptr != NULL &&
dtype == LIBUSB_DT_DEVICE_CAPABILITY) {
- if (index != ptr->bNumDeviceCapabilities) {
+ if (index != ptr->bNumDeviceCaps) {
ptr->dev_capability[index] = malloc(dlen);
if (ptr->dev_capability[index] == NULL) {
libusb_free_bos_descriptor(ptr);
@@ -542,7 +543,7 @@ libusb_parse_bos_descriptor(const void *buf, int len,
}
if (ptr != NULL) {
- ptr->bNumDeviceCapabilities = index;
+ ptr->bNumDeviceCaps = index;
return (0); /* success */
}
@@ -557,7 +558,7 @@ libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
if (bos == NULL)
return;
- for (i = 0; i != bos->bNumDeviceCapabilities; i++)
+ for (i = 0; i != bos->bNumDeviceCaps; i++)
free(bos->dev_capability[i]);
free(bos->dev_capability);
free(bos);
diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c
index 369539d4512e..9c46d4926bfa 100644
--- a/lib/libusb/libusb10_hotplug.c
+++ b/lib/libusb/libusb10_hotplug.c
@@ -414,3 +414,21 @@ void libusb_hotplug_deregister_callback(libusb_context *ctx,
free(handle);
}
+
+void *
+libusb_hotplug_get_user_data(struct libusb_context *ctx,
+ libusb_hotplug_callback_handle callback_handle)
+{
+ libusb_hotplug_callback_handle handle;
+
+ ctx = GET_CONTEXT(ctx);
+
+ HOTPLUG_LOCK(ctx);
+ TAILQ_FOREACH(handle, &ctx->hotplug_cbh, entry) {
+ if (handle == callback_handle)
+ break;
+ }
+ HOTPLUG_UNLOCK(ctx);
+
+ return (handle);
+}
diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c
index f1e31c2a7416..c99586ff650d 100644
--- a/lib/libusb/libusb10_io.c
+++ b/lib/libusb/libusb10_io.c
@@ -108,7 +108,7 @@ libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
int i;
int err;
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub enter");
nfds = 0;
i = 0;
@@ -230,7 +230,7 @@ do_done:
/* Wakeup other waiters */
pthread_cond_broadcast(&ctx->ctx_cond);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub complete");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub complete");
return (err);
}
@@ -314,7 +314,7 @@ libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
int err;
ctx = GET_CONTEXT(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_wait_for_event enter");
if (tv == NULL) {
pthread_cond_wait(&ctx->ctx_cond,
@@ -358,7 +358,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx,
ctx = GET_CONTEXT(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed enter");
libusb_lock_events(ctx);
@@ -374,7 +374,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx,
libusb_unlock_events(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed exit");
return (err);
}
@@ -523,7 +523,7 @@ libusb10_do_transfer_cb(struct libusb_transfer *transfer)
ctx = libusb10_get_context_by_device_handle(transfer->dev_handle);
- DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "sync I/O done");
pdone = transfer->user_data;
*pdone = 1;
@@ -613,12 +613,12 @@ libusb_bulk_transfer(libusb_device_handle *devh,
ctx = libusb10_get_context_by_device_handle(devh);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer enter");
ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
timeout, LIBUSB_TRANSFER_TYPE_BULK);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer leave");
return (ret);
}
@@ -632,12 +632,12 @@ libusb_interrupt_transfer(libusb_device_handle *devh,
ctx = libusb10_get_context_by_device_handle(devh);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer enter");
ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer leave");
return (ret);
}
@@ -781,6 +781,19 @@ libusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
}
void
+libusb_fill_bulk_stream_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *dev_handle, unsigned char endpoint,
+ uint32_t stream_id, unsigned char *buffer, int length,
+ libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
+{
+ libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer,
+ length, callback, user_data, timeout);
+ transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
+
+ libusb_transfer_set_stream_id(transfer, stream_id);
+}
+
+void
libusb_fill_iso_transfer(struct libusb_transfer *transfer,
libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
int length, int npacket, libusb_transfer_cb_fn callback,
@@ -842,3 +855,12 @@ libusb_transfer_get_stream_id(struct libusb_transfer *transfer)
/* get stream ID */
return (sxfer->stream_id);
}
+
+void
+libusb_free_pollfds(const struct libusb_pollfd **pollfds)
+{
+ if (pollfds == NULL)
+ return;
+
+ free(pollfds);
+}
diff --git a/lib/libusb/libusb20_desc.h b/lib/libusb/libusb20_desc.h
index 017148a34b1c..0f7c9294ebc8 100644
--- a/lib/libusb/libusb20_desc.h
+++ b/lib/libusb/libusb20_desc.h
@@ -298,11 +298,15 @@ LIBUSB20_MAKE_STRUCT(LIBUSB20_USB_20_DEVCAP_DESC);
LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_USB_DEVCAP_DESC);
+#ifndef bNumDeviceCapabilities
+#define bNumDeviceCapabilities bNumDeviceCaps
+#endif
+
#define LIBUSB20_BOS_DESCRIPTOR(m,n) \
m(n, UINT8_T, bLength, ) \
m(n, UINT8_T, bDescriptorType, ) \
m(n, UINT16_T, wTotalLength, ) \
- m(n, UINT8_T, bNumDeviceCapabilities, ) \
+ m(n, UINT8_T, bNumDeviceCaps, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_BOS_DESCRIPTOR);
diff --git a/lib/ncurses/tinfo/Makefile b/lib/ncurses/tinfo/Makefile
index 920bd6e5559c..476df54bb72a 100644
--- a/lib/ncurses/tinfo/Makefile
+++ b/lib/ncurses/tinfo/Makefile
@@ -259,10 +259,18 @@ term.h: MKterm.h.awk edit_cfg.sh Caps Caps-ncurses
sh ${NCURSES_DIR}/include/edit_cfg.sh ${NCURSES_CFG_H} $@.new
mv -f $@.new $@
+# Avoid hard-coding absolute source paths if requested.
+.if ${MK_REPRODUCIBLE_BUILD} != "no"
+NCURSES_SRCTOP=/usr/src
+.else
+NCURSES_SRCTOP=${SRCTOP}
+.endif
+
curses.h: curses.head MKkey_defs.sh Caps Caps-ncurses
cat curses.head > $@.new
AWK=${AWK} _POSIX2_VERSION=199209 sh ${NCURSES_DIR}/include/MKkey_defs.sh \
${NCURSES_DIR}/include/Caps ${NCURSES_DIR}/include/Caps-ncurses >> $@.new
+ sed -i '' 's|${SRCTOP}|${NCURSES_SRCTOP}|g' $@.new
cat ${NCURSES_DIR}/include/curses.wide >> $@.new
cat ${NCURSES_DIR}/include/curses.tail >> $@.new
mv -f $@.new $@
@@ -387,6 +395,7 @@ unctrl.h: unctrl.h.in
terminfo.5: MKterminfo.sh terminfo.head Caps
sh ${NCURSES_DIR}/man/MKterminfo.sh ${NCURSES_DIR}/man/terminfo.head \
${NCURSES_DIR}/include/Caps ${NCURSES_DIR}/man/terminfo.tail >$@
+ sed -i '' 's|${SRCTOP}|${NCURSES_SRCTOP}|g' $@
CLEANFILES+= terminfo.5