diff options
Diffstat (limited to 'lib')
96 files changed, 1854 insertions, 519 deletions
diff --git a/lib/lib80211/regdomain.xml b/lib/lib80211/regdomain.xml index 9116e54c31cf..16b74445f429 100644 --- a/lib/lib80211/regdomain.xml +++ b/lib/lib80211/regdomain.xml @@ -494,6 +494,10 @@ <flags>IEEE80211_CHAN_PASSIVE</flags> <flags>IEEE80211_CHAN_DFS</flags> </band> + <band> + <freqband ref="A20_5745_5865"/> + <maxpower>13</maxpower> + </band> </netband> <netband mode="11ng"> <band> @@ -548,6 +552,14 @@ <flags>IEEE80211_CHAN_PASSIVE</flags> <flags>IEEE80211_CHAN_DFS</flags> </band> + <band> + <freqband ref="NA20_5745_5865"/> + <maxpower>13</maxpower> + </band> + <band> + <freqband ref="NA40_5745_5845"/> + <maxpower>13</maxpower> + </band> </netband> <netband mode="11ac"> <!-- 5150-5250/80, 200 mW, indoor --> @@ -645,7 +657,7 @@ <flags>IEEE80211_CHAN_DFS</flags> </band> <band> - <freqband ref="AC2_5745_5805_40"/> + <freqband ref="AC2_5745_5845_40"/> <maxpower>13</maxpower> <flags>IEEE80211_CHAN_HT40</flags> <flags>IEEE80211_CHAN_VHT40</flags> @@ -658,13 +670,6 @@ <flags>IEEE80211_CHAN_VHT80</flags> <flags>IEEE80211_CHAN_DFS</flags> </band> - <band> - <freqband ref="AC2_5745_5885_160"/> - <maxpower>13</maxpower> - <flags>IEEE80211_CHAN_HT40</flags> - <flags>IEEE80211_CHAN_VHT160</flags> - <flags>IEEE80211_CHAN_DFS</flags> - </band> </netband> </rd> @@ -2304,6 +2309,29 @@ <chanwidth>20</chanwidth> <chansep>20</chansep> <flags>IEEE80211_CHAN_A</flags> </freqband> +<freqband id="A20_5745_5865"> + <freqstart>5745</freqstart> + <freqend>5865</freqend> + <chanwidth>20</chanwidth> + <chansep>20</chansep> + <flags>IEEE80211_CHAN_A</flags> +</freqband> +<freqband id="NA20_5745_5865"> + <freqstart>5745</freqstart> + <freqend>5865</freqend> + <chanwidth>20</chanwidth> + <chansep>20</chansep> + <flags>IEEE80211_CHAN_A</flags> + <flags>IEEE80211_CHAN_HT20</flags> +</freqband> +<freqband id="NA40_5745_5845"> + <freqstart>5745</freqstart> + <freqend>5845</freqend> + <chanwidth>40</chanwidth> + <chansep>20</chansep> + <flags>IEEE80211_CHAN_A</flags> + <flags>IEEE80211_CHAN_HT40</flags> +</freqband> <freqband id="F1_5660_5700"> <freqstart>5660</freqstart> <freqend>5700</freqend> <chanwidth>20</chanwidth> <chansep>20</chansep> diff --git a/lib/libbsnmp/libbsnmp/Makefile b/lib/libbsnmp/libbsnmp/Makefile index 6bdb4003fdf4..2e2770b56c4a 100644 --- a/lib/libbsnmp/libbsnmp/Makefile +++ b/lib/libbsnmp/libbsnmp/Makefile @@ -7,7 +7,7 @@ CONTRIB= ${SRCTOP}/contrib/bsnmp/lib .PATH: ${CONTRIB} LIB= bsnmp -SHLIB_MAJOR= 6 +SHLIB_MAJOR= 7 LD_FATAL_WARNINGS= no CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c index 7a66f5443d94..cc96fb5ce326 100644 --- a/lib/libc/db/hash/hash.c +++ b/lib/libc/db/hash/hash.c @@ -120,7 +120,8 @@ __hash_open(const char *file, int flags, int mode, if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1) RETURN_ERROR(errno, error0); new_table = _fstat(hashp->fp, &statbuf) == 0 && - statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY; + statbuf.st_size == 0 && + ((flags & O_ACCMODE) != O_RDONLY || (flags & O_CREAT) != 0); } else new_table = 1; 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/dup3.3 b/lib/libc/gen/dup3.3 index f2798930797b..338a9ae74c64 100644 --- a/lib/libc/gen/dup3.3 +++ b/lib/libc/gen/dup3.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 16, 2013 +.Dd May 17, 2025 .Dt DUP3 3 .Os .Sh NAME @@ -47,6 +47,11 @@ The close-on-exec flag on the new file descriptor is determined by the bit in .Fa flags . .Pp +The close-on-fork flag on the new file descriptor is determined by the +.Dv O_CLOFORK +bit in +.Fa flags . +.Pp If .Fa oldd \*(Ne @@ -91,7 +96,9 @@ argument. The .Fa flags argument has bits set other than -.Dv O_CLOEXEC . +.Dv O_CLOEXEC +or +.Dv O_CLOFORK . .El .Sh SEE ALSO .Xr accept 2 , @@ -112,3 +119,7 @@ The .Fn dup3 function appeared in .Fx 10.0 . +The +.Dv O_CLOFORK +flag appeared in +.Fx 15.0 . diff --git a/lib/libc/gen/dup3.c b/lib/libc/gen/dup3.c index fca1e99fb47b..1401c1f5b607 100644 --- a/lib/libc/gen/dup3.c +++ b/lib/libc/gen/dup3.c @@ -39,21 +39,22 @@ int __dup3(int, int, int); int __dup3(int oldfd, int newfd, int flags) { - int how; + int fdflags; if (oldfd == newfd) { errno = EINVAL; return (-1); } - if (flags & ~O_CLOEXEC) { + if ((flags & ~(O_CLOEXEC | O_CLOFORK)) != 0) { errno = EINVAL; return (-1); } - how = (flags & O_CLOEXEC) ? F_DUP2FD_CLOEXEC : F_DUP2FD; + fdflags = ((flags & O_CLOEXEC) != 0 ? FD_CLOEXEC : 0) | + ((flags & O_CLOFORK) != 0 ? FD_CLOFORK : 0); - return (_fcntl(oldfd, how, newfd)); + return (_fcntl(oldfd, F_DUP3FD | (fdflags << F_DUP3FD_SHIFT), newfd)); } __weak_reference(__dup3, dup3); 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 24ea242560b8..16cbe27693e7 100644 --- a/lib/libc/gen/err.c +++ b/lib/libc/gen/err.c @@ -30,9 +30,12 @@ */ #include "namespace.h" +#include <sys/exterrvar.h> #include <err.h> #include <errno.h> +#include <exterr.h> #include <stdarg.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -43,6 +46,11 @@ static FILE *err_file; /* file to use for error output */ static void (*err_exit)(int); +static void verrci(bool doexterr, int eval, int code, const char *fmt, + va_list ap) __printf0like(4, 0) __dead2; +static void vwarnci(bool doexterr, int code, const char *fmt, va_list ap) + __printf0like(3, 0); + /* * This is declared to take a `void *' so that the caller is not required * to include <stdio.h> first. However, it is really a `FILE *', and the @@ -70,14 +78,14 @@ _err(int eval, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - verrc(eval, errno, fmt, ap); + verrci(true, eval, errno, fmt, ap); va_end(ap); } void verr(int eval, const char *fmt, va_list ap) { - verrc(eval, errno, fmt, ap); + verrci(true, eval, errno, fmt, ap); } void @@ -85,13 +93,24 @@ errc(int eval, int code, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - verrc(eval, code, fmt, ap); + verrci(false, eval, code, fmt, ap); va_end(ap); } void verrc(int eval, int code, const char *fmt, va_list ap) { + verrci(false, eval, code, fmt, ap); +} + +static void +vexterr(bool doexterr, int code, const char *fmt, va_list ap) +{ + char exterr[UEXTERROR_MAXLEN]; /* libc knows the buffer size */ + int extstatus; + + if (doexterr) + extstatus = uexterr_gettext(exterr, sizeof(exterr)); if (err_file == NULL) err_set_file(NULL); fprintf(err_file, "%s: ", _getprogname()); @@ -99,7 +118,16 @@ verrc(int eval, int code, const char *fmt, va_list ap) vfprintf(err_file, fmt, ap); fprintf(err_file, ": "); } - fprintf(err_file, "%s\n", strerror(code)); + fprintf(err_file, "%s", strerror(code)); + if (doexterr && extstatus == 0 && exterr[0] != '\0') + fprintf(err_file, " (extended error %s)", exterr); + fprintf(err_file, "\n"); +} + +static void +verrci(bool doexterr, int eval, int code, const char *fmt, va_list ap) +{ + vexterr(doexterr, code, fmt, ap); if (err_exit) err_exit(eval); exit(eval); @@ -157,17 +185,16 @@ warnc(int code, const char *fmt, ...) void vwarnc(int code, const char *fmt, va_list ap) { + vwarnci(false, code, fmt, ap); +} + +static void +vwarnci(bool doexterr, int code, const char *fmt, va_list ap) +{ int saved_errno; saved_errno = errno; - if (err_file == NULL) - err_set_file(NULL); - fprintf(err_file, "%s: ", _getprogname()); - if (fmt != NULL) { - vfprintf(err_file, fmt, ap); - fprintf(err_file, ": "); - } - fprintf(err_file, "%s\n", strerror(code)); + vexterr(doexterr, code, fmt, ap); errno = saved_errno; } 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 32b57ffb6e1a..e8ddfbd578e3 100644 --- a/lib/libc/gen/uexterr_format.c +++ b/lib/libc/gen/uexterr_format.c @@ -20,12 +20,16 @@ __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); } - snprintf(buf, bufsz, - "errno %d category %u (src line %u) p1 %#jx p2 %#jx %s", - ue->error, ue->cat, ue->src_line, - (uintmax_t)ue->p1, (uintmax_t)ue->p2, ue->msg); + if (ue->msg[0] == '\0') { + snprintf(buf, bufsz, + "errno %d category %u (src line %u) p1 %#jx p2 %#jx", + ue->error, ue->cat, ue->src_line, + (uintmax_t)ue->p1, (uintmax_t)ue->p2); + } else { + strlcpy(buf, ue->msg, bufsz); + } return (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/net/gethostbydns.c b/lib/libc/net/gethostbydns.c index b29fa1cdd845..216fc9bcf9a4 100644 --- a/lib/libc/net/gethostbydns.c +++ b/lib/libc/net/gethostbydns.c @@ -74,8 +74,10 @@ #define SPRINTF(x) ((size_t)sprintf x) +#ifdef DEBUG static const char AskedForGot[] = "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; +#endif #ifdef RESOLVSORT static void addrsort(char **, int, res_state); @@ -299,8 +301,10 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype, switch (type) { case T_PTR: if (strcasecmp(tname, bp) != 0) { +#ifdef DEBUG syslog(LOG_NOTICE|LOG_AUTH, AskedForGot, qname, bp); +#endif cp += n; continue; /* XXX - had_error++ ? */ } @@ -347,8 +351,10 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype, case T_A: case T_AAAA: if (strcasecmp(he->h_name, bp) != 0) { +#ifdef DEBUG syslog(LOG_NOTICE|LOG_AUTH, AskedForGot, he->h_name, bp); +#endif cp += n; continue; /* XXX - had_error++ ? */ } diff --git a/lib/libc/net/res_config.h b/lib/libc/net/res_config.h index f049d6817b7a..39a1b5f1486f 100644 --- a/lib/libc/net/res_config.h +++ b/lib/libc/net/res_config.h @@ -1,5 +1,5 @@ -#define DEBUG 1 /* enable debugging code (needed for dig) */ +//#define DEBUG /* enable debugging code */ #define RESOLVSORT /* allow sorting of addresses in gethostbyname */ -#undef SUNSECURITY /* verify gethostbyaddr() calls - WE DON'T NEED IT */ +//#define SUNSECURITY /* verify gethostbyaddr() calls */ #define MULTI_PTRS_ARE_ALIASES 1 /* fold multiple PTR records into aliases */ 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/resolv/res_debug.h b/lib/libc/resolv/res_debug.h index dd048116fb49..ccae03e625aa 100644 --- a/lib/libc/resolv/res_debug.h +++ b/lib/libc/resolv/res_debug.h @@ -23,7 +23,7 @@ #ifndef DEBUG # define Dprint(cond, args) /*empty*/ # define DprintQ(cond, args, query, size) /*empty*/ -# define Aerror(statp, file, string, error, address) /*empty*/ +# define Aerror(statp, file, string, error, address, alen) /*empty*/ # define Perror(statp, file, string, error) /*empty*/ #else # define Dprint(cond, args) if (cond) {fprintf args;} else {} diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c index 70d6bc6d3bf2..71ab2dcb7038 100644 --- a/lib/libc/resolv/res_init.c +++ b/lib/libc/resolv/res_init.c @@ -108,12 +108,6 @@ #include "res_private.h" -/*% Options. Should all be left alone. */ -#define RESOLVSORT -#ifndef DEBUG -#define DEBUG -#endif - #ifdef SOLARIS2 #include <sys/systeminfo.h> #endif diff --git a/lib/libc/resolv/res_mkquery.c b/lib/libc/resolv/res_mkquery.c index 0c15def5d117..f6767a92375c 100644 --- a/lib/libc/resolv/res_mkquery.c +++ b/lib/libc/resolv/res_mkquery.c @@ -76,11 +76,6 @@ #include <string.h> #include "port_after.h" -/* Options. Leave them on. */ -#ifndef DEBUG -#define DEBUG -#endif - extern const char *_res_opcodes[]; /*% diff --git a/lib/libc/resolv/res_mkupdate.c b/lib/libc/resolv/res_mkupdate.c index e5a3cb702cda..3f595dc4ec08 100644 --- a/lib/libc/resolv/res_mkupdate.c +++ b/lib/libc/resolv/res_mkupdate.c @@ -48,10 +48,6 @@ #include "port_after.h" -/* Options. Leave them on. */ -#ifndef DEBUG -#define DEBUG -#endif #define MAXPORT 1024 static int getnum_str(u_char **, u_char *); diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c index e9c628ad8d47..f26d59e522b4 100644 --- a/lib/libc/resolv/res_query.c +++ b/lib/libc/resolv/res_query.c @@ -81,11 +81,6 @@ #include <unistd.h> #include "port_after.h" -/* Options. Leave them on. */ -#ifndef DEBUG -#define DEBUG -#endif - #if PACKETSZ > 1024 #define MAXPACKET PACKETSZ #else diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c index 3fb627b83d55..08c3aed7f934 100644 --- a/lib/libc/resolv/res_send.c +++ b/lib/libc/resolv/res_send.c @@ -112,10 +112,6 @@ #include "un-namespace.h" -/* Options. Leave them on. */ -#ifndef DEBUG -#define DEBUG -#endif #include "res_debug.h" #include "res_private.h" @@ -138,15 +134,12 @@ static int send_dg(res_state, const u_char *, int, u_char *, int, int *, int, int, int *, int *); +#ifdef DEBUG static void Aerror(const res_state, FILE *, const char *, int, const struct sockaddr *, int); static void Perror(const res_state, FILE *, const char *, int); -static int sock_eq(struct sockaddr *, struct sockaddr *); -#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) -static int pselect(int, void *, void *, void *, - struct timespec *, - const sigset_t *); #endif +static int sock_eq(struct sockaddr *, struct sockaddr *); void res_pquery(const res_state, const u_char *, int, FILE *); static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; @@ -302,7 +295,9 @@ res_nsend(res_state statp, #ifdef USE_KQUEUE int kq; #endif +#ifdef DEBUG char abuf[NI_MAXHOST]; +#endif /* No name servers or res_init() failure */ if (statp->nscount == 0 || EXT(statp).ext == NULL) { @@ -418,10 +413,10 @@ res_nsend(res_state statp, */ for (tries = 0; tries < statp->retry; tries++) { for (ns = 0; ns < statp->nscount; ns++) { - struct sockaddr *nsap; - int nsaplen; - nsap = get_nsaddr(statp, ns); - nsaplen = get_salen(nsap); + struct sockaddr *nsap = get_nsaddr(statp, ns); +#ifdef DEBUG + int nsaplen = get_salen(nsap); +#endif statp->_flags &= ~RES_F_LASTMASK; statp->_flags |= (ns << RES_F_LASTSHIFT); same_ns: @@ -1088,6 +1083,7 @@ send_dg(res_state statp, return (resplen); } +#ifdef DEBUG static void Aerror(const res_state statp, FILE *file, const char *string, int error, const struct sockaddr *address, int alen) @@ -1119,6 +1115,7 @@ Perror(const res_state statp, FILE *file, const char *string, int error) { string, strerror(error)); errno = save; } +#endif static int sock_eq(struct sockaddr *a, struct sockaddr *b) { @@ -1145,29 +1142,3 @@ sock_eq(struct sockaddr *a, struct sockaddr *b) { return 0; } } - -#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) -/* XXX needs to move to the porting library. */ -static int -pselect(int nfds, void *rfds, void *wfds, void *efds, - struct timespec *tsp, const sigset_t *sigmask) -{ - struct timeval tv, *tvp; - sigset_t sigs; - int n; - - if (tsp) { - tvp = &tv; - tv = evTimeVal(*tsp); - } else - tvp = NULL; - if (sigmask) - sigprocmask(SIG_SETMASK, sigmask, &sigs); - n = select(nfds, rfds, wfds, efds, tvp); - if (sigmask) - sigprocmask(SIG_SETMASK, &sigs, NULL); - if (tsp) - *tsp = evTimeSpec(tv); - return (n); -} -#endif 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/string/memchr.3 b/lib/libc/string/memchr.3 index f5d1fe5d5c7f..c50e932d3382 100644 --- a/lib/libc/string/memchr.3 +++ b/lib/libc/string/memchr.3 @@ -34,7 +34,7 @@ .Os .Sh NAME .Nm memchr -.Nd locate byte in byte string +.Nd locate byte in memory object .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -51,8 +51,11 @@ locates the first occurrence of .Fa c (converted to an .Vt "unsigned char" ) -in string -.Fa b . +in object +.Fa b , +limited to at most +.Fa len +characters. .Pp The .Fn memrchr @@ -60,16 +63,19 @@ function behaves like .Fn memchr , except that it locates the last occurrence of .Fa c -in string -.Fa b . +in object +.Fa b , +limited to the first +.Fa len +characters. .Sh RETURN VALUES The .Fn memchr and .Fn memrchr -functions -return a pointer to the byte located, -or NULL if no such byte exists within +functions return a pointer to the byte located, or +.Dv NULL +if no such byte exists within .Fa len bytes. .Sh SEE ALSO diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile index f1f33bd2bafc..54b38b94a581 100644 --- a/lib/libc/tests/db/Makefile +++ b/lib/libc/tests/db/Makefile @@ -7,6 +7,8 @@ PROGS+= h_lfsr ${PACKAGE}FILES+= README +ATF_TESTS_C+= dbm_open_test + NETBSD_ATF_TESTS_C+= db_hash_seq_test NETBSD_ATF_TESTS_SH+= db_test ATF_TESTS_SH_SED_db_test= -e 's,/bin/csh,/bin/cat,g' diff --git a/lib/libc/tests/db/dbm_open_test.c b/lib/libc/tests/db/dbm_open_test.c new file mode 100644 index 000000000000..18d398e16b2a --- /dev/null +++ b/lib/libc/tests/db/dbm_open_test.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2025 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/mman.h> + +#include <fcntl.h> +#include <ndbm.h> +#include <stdio.h> + +#include <atf-c.h> + +ATF_TC(dbm_open_missing_test); +ATF_TC_HEAD(dbm_open_missing_test, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test dbm_open when creating a new database"); +} + +ATF_TC_BODY(dbm_open_missing_test, tc) +{ + const char *path = "tmp"; + const char *dbname = "tmp.db"; + + /* + * POSIX.1 specifies that a missing database file should + * always get created if O_CREAT is present, except when + * O_EXCL is specified as well. + */ + ATF_CHECK(dbm_open(path, O_RDONLY, _PROT_ALL) == NULL); + ATF_REQUIRE(!atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT, _PROT_ALL) != NULL); + ATF_REQUIRE(atf_utils_file_exists(dbname)); + ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT | O_EXCL, _PROT_ALL) == NULL); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dbm_open_missing_test); + return (atf_no_error()); +} 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/libcasper/services/cap_net/tests/net_test.c b/lib/libcasper/services/cap_net/tests/net_test.c index e1045341fe47..adf5773233c8 100644 --- a/lib/libcasper/services/cap_net/tests/net_test.c +++ b/lib/libcasper/services/cap_net/tests/net_test.c @@ -331,7 +331,11 @@ test_extend_mode(cap_channel_t *capnet, int current) } } -ATF_TC_WITHOUT_HEAD(capnet__getnameinfo); +ATF_TC(capnet__getnameinfo); +ATF_TC_HEAD(capnet__getnameinfo, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__getnameinfo, tc) { cap_channel_t *capnet; @@ -344,7 +348,11 @@ ATF_TC_BODY(capnet__getnameinfo, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__connect); +ATF_TC(capnet__connect); +ATF_TC_HEAD(capnet__connect, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__connect, tc) { cap_channel_t *capnet; @@ -356,7 +364,11 @@ ATF_TC_BODY(capnet__connect, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__bind); +ATF_TC(capnet__bind); +ATF_TC_HEAD(capnet__bind, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__bind, tc) { cap_channel_t *capnet; @@ -368,7 +380,11 @@ ATF_TC_BODY(capnet__bind, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__getaddrinfo); +ATF_TC(capnet__getaddrinfo); +ATF_TC_HEAD(capnet__getaddrinfo, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__getaddrinfo, tc) { cap_channel_t *capnet; @@ -386,7 +402,11 @@ ATF_TC_BODY(capnet__getaddrinfo, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__gethostbyname); +ATF_TC(capnet__gethostbyname); +ATF_TC_HEAD(capnet__gethostbyname, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__gethostbyname, tc) { cap_channel_t *capnet; @@ -398,7 +418,11 @@ ATF_TC_BODY(capnet__gethostbyname, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__gethostbyaddr); +ATF_TC(capnet__gethostbyaddr); +ATF_TC_HEAD(capnet__gethostbyaddr, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__gethostbyaddr, tc) { cap_channel_t *capnet; @@ -411,7 +435,11 @@ ATF_TC_BODY(capnet__gethostbyaddr, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__getnameinfo_buffer); +ATF_TC(capnet__getnameinfo_buffer); +ATF_TC_HEAD(capnet__getnameinfo_buffer, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__getnameinfo_buffer, tc) { cap_channel_t *chan; @@ -450,7 +478,11 @@ ATF_TC_BODY(capnet__getnameinfo_buffer, tc) cap_close(chan); } -ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name_mode); +ATF_TC(capnet__limits_addr2name_mode); +ATF_TC_HEAD(capnet__limits_addr2name_mode, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_addr2name_mode, tc) { cap_channel_t *capnet; @@ -481,7 +513,11 @@ ATF_TC_BODY(capnet__limits_addr2name_mode, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name_family); +ATF_TC(capnet__limits_addr2name_family); +ATF_TC_HEAD(capnet__limits_addr2name_family, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_addr2name_family, tc) { cap_channel_t *capnet; @@ -526,7 +562,11 @@ ATF_TC_BODY(capnet__limits_addr2name_family, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name); +ATF_TC(capnet__limits_addr2name); +ATF_TC_HEAD(capnet__limits_addr2name, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_addr2name, tc) { cap_channel_t *capnet; @@ -580,7 +620,11 @@ ATF_TC_BODY(capnet__limits_addr2name, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name_mode); +ATF_TC(capnet__limits_deprecated_addr2name_mode); +ATF_TC_HEAD(capnet__limits_deprecated_addr2name_mode, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_deprecated_addr2name_mode, tc) { cap_channel_t *capnet; @@ -609,7 +653,11 @@ ATF_TC_BODY(capnet__limits_deprecated_addr2name_mode, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name_family); +ATF_TC(capnet__limits_deprecated_addr2name_family); +ATF_TC_HEAD(capnet__limits_deprecated_addr2name_family, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_deprecated_addr2name_family, tc) { cap_channel_t *capnet; @@ -660,7 +708,11 @@ ATF_TC_BODY(capnet__limits_deprecated_addr2name_family, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name); +ATF_TC(capnet__limits_deprecated_addr2name); +ATF_TC_HEAD(capnet__limits_deprecated_addr2name, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_deprecated_addr2name, tc) { cap_channel_t *capnet; @@ -712,7 +764,11 @@ ATF_TC_BODY(capnet__limits_deprecated_addr2name, tc) } -ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_mode); +ATF_TC(capnet__limits_name2addr_mode); +ATF_TC_HEAD(capnet__limits_name2addr_mode, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_name2addr_mode, tc) { cap_channel_t *capnet; @@ -744,7 +800,11 @@ ATF_TC_BODY(capnet__limits_name2addr_mode, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts); +ATF_TC(capnet__limits_name2addr_hosts); +ATF_TC_HEAD(capnet__limits_name2addr_hosts, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_name2addr_hosts, tc) { cap_channel_t *capnet; @@ -797,7 +857,11 @@ ATF_TC_BODY(capnet__limits_name2addr_hosts, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts_servnames_strict); +ATF_TC(capnet__limits_name2addr_hosts_servnames_strict); +ATF_TC_HEAD(capnet__limits_name2addr_hosts_servnames_strict, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_strict, tc) { cap_channel_t *capnet; @@ -829,7 +893,11 @@ ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_strict, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts_servnames_mix); +ATF_TC(capnet__limits_name2addr_hosts_servnames_mix); +ATF_TC_HEAD(capnet__limits_name2addr_hosts_servnames_mix, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_mix, tc) { cap_channel_t *capnet; @@ -882,7 +950,11 @@ ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_mix, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_family); +ATF_TC(capnet__limits_name2addr_family); +ATF_TC_HEAD(capnet__limits_name2addr_family, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_name2addr_family, tc) { cap_channel_t *capnet; @@ -941,7 +1013,11 @@ ATF_TC_BODY(capnet__limits_name2addr_family, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_mode); +ATF_TC(capnet__limits_deprecated_name2addr_mode); +ATF_TC_HEAD(capnet__limits_deprecated_name2addr_mode, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_deprecated_name2addr_mode, tc) { cap_channel_t *capnet; @@ -972,7 +1048,11 @@ ATF_TC_BODY(capnet__limits_deprecated_name2addr_mode, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_hosts); +ATF_TC(capnet__limits_deprecated_name2addr_hosts); +ATF_TC_HEAD(capnet__limits_deprecated_name2addr_hosts, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_deprecated_name2addr_hosts, tc) { cap_channel_t *capnet; @@ -1011,7 +1091,11 @@ ATF_TC_BODY(capnet__limits_deprecated_name2addr_hosts, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_family); +ATF_TC(capnet__limits_deprecated_name2addr_family); +ATF_TC_HEAD(capnet__limits_deprecated_name2addr_family, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_deprecated_name2addr_family, tc) { cap_channel_t *capnet; @@ -1065,7 +1149,11 @@ ATF_TC_BODY(capnet__limits_deprecated_name2addr_family, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_bind_mode); +ATF_TC(capnet__limits_bind_mode); +ATF_TC_HEAD(capnet__limits_bind_mode, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_bind_mode, tc) { cap_channel_t *capnet; @@ -1097,7 +1185,11 @@ ATF_TC_BODY(capnet__limits_bind_mode, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_bind); +ATF_TC(capnet__limits_bind); +ATF_TC_HEAD(capnet__limits_bind, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_bind, tc) { cap_channel_t *capnet; @@ -1122,7 +1214,11 @@ ATF_TC_BODY(capnet__limits_bind, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_connect_mode); +ATF_TC(capnet__limits_connect_mode); +ATF_TC_HEAD(capnet__limits_connect_mode, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_connect_mode, tc) { cap_channel_t *capnet; @@ -1154,7 +1250,11 @@ ATF_TC_BODY(capnet__limits_connect_mode, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_connect_dns_mode); +ATF_TC(capnet__limits_connect_dns_mode); +ATF_TC_HEAD(capnet__limits_connect_dns_mode, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_connect_dns_mode, tc) { cap_channel_t *capnet; @@ -1186,7 +1286,11 @@ ATF_TC_BODY(capnet__limits_connect_dns_mode, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_connect); +ATF_TC(capnet__limits_connect); +ATF_TC_HEAD(capnet__limits_connect, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_connect, tc) { cap_channel_t *capnet; @@ -1230,7 +1334,11 @@ ATF_TC_BODY(capnet__limits_connect, tc) cap_close(capnet); } -ATF_TC_WITHOUT_HEAD(capnet__limits_connecttodns); +ATF_TC(capnet__limits_connecttodns); +ATF_TC_HEAD(capnet__limits_connecttodns, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_connecttodns, tc) { cap_channel_t *capnet; @@ -1279,7 +1387,11 @@ ATF_TC_BODY(capnet__limits_connecttodns, tc) } -ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_connecttodns); +ATF_TC(capnet__limits_deprecated_connecttodns); +ATF_TC_HEAD(capnet__limits_deprecated_connecttodns, tc) +{ + atf_tc_set_md_var(tc, "require.config", "allow_network_access"); +} ATF_TC_BODY(capnet__limits_deprecated_connecttodns, tc) { cap_channel_t *capnet; 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..6b38fd286596 100644 --- a/lib/libnvmf/libnvmf.h +++ b/lib/libnvmf/libnvmf.h @@ -111,8 +111,13 @@ const void *nvmf_capsule_cqe(const struct nvmf_capsule *nc); /* Return a string name for a transport type. */ const char *nvmf_transport_type(uint8_t trtype); -/* Validate a NVMe Qualified Name. */ +/* + * Validate a NVMe Qualified Name. The second version enforces + * stricter checks inline with the specification. The first version + * enforces more minimal checks. + */ bool nvmf_nqn_valid(const char *nqn); +bool nvmf_nqn_valid_strict(const char *nqn); /* Controller-specific APIs. */ @@ -342,7 +347,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 +376,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_controller.c b/lib/libnvmf/nvmf_controller.c index 971dccbe039e..f26f11633e03 100644 --- a/lib/libnvmf/nvmf_controller.c +++ b/lib/libnvmf/nvmf_controller.c @@ -7,6 +7,7 @@ #include <sys/utsname.h> #include <assert.h> +#include <ctype.h> #include <errno.h> #include <string.h> #include <unistd.h> @@ -15,6 +16,55 @@ #include "internal.h" #include "nvmft_subr.h" +bool +nvmf_nqn_valid_strict(const char *nqn) +{ + size_t len; + + if (!nvmf_nqn_valid(nqn)) + return (false); + + /* + * Stricter checks from the spec. Linux does not seem to + * require these. + */ + len = strlen(nqn); + + /* + * NVMF_NQN_MIN_LEN does not include '.' and require at least + * one character of a domain name. + */ + if (len < NVMF_NQN_MIN_LEN + 2) + return (false); + if (memcmp("nqn.", nqn, strlen("nqn.")) != 0) + return (false); + nqn += strlen("nqn."); + + /* Next 4 digits must be a year. */ + for (u_int i = 0; i < 4; i++) { + if (!isdigit(nqn[i])) + return (false); + } + nqn += 4; + + /* '-' between year and month. */ + if (nqn[0] != '-') + return (false); + nqn++; + + /* 2 digit month. */ + for (u_int i = 0; i < 2; i++) { + if (!isdigit(nqn[i])) + return (false); + } + nqn += 2; + + /* '.' between month and reverse domain name. */ + if (nqn[0] != '.') + return (false); + return (true); +} + void nvmf_init_cqe(void *cqe, const struct nvmf_capsule *nc, uint16_t status) { 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/libopenbsd/Makefile b/lib/libopenbsd/Makefile index 675ed476c51d..dca1c08b0aed 100644 --- a/lib/libopenbsd/Makefile +++ b/lib/libopenbsd/Makefile @@ -2,7 +2,8 @@ PACKAGE=lib${LIB} LIB= openbsd SRCS= imsg-buffer.c \ imsg.c \ - ohash.c + ohash.c \ + recallocarray.c .if !defined(BOOTSTRAPPING) # Skip getdtablecount.c when bootstrapping since it doesn't compile for Linux # and is not used by any of the bootstrap tools diff --git a/lib/libopenbsd/recallocarray.c b/lib/libopenbsd/recallocarray.c new file mode 100644 index 000000000000..11e1fda744c7 --- /dev/null +++ b/lib/libopenbsd/recallocarray.c @@ -0,0 +1,82 @@ +/* $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 <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.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 *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 ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + newnmemb > 0 && SIZE_MAX / newnmemb < size) { + errno = ENOMEM; + return NULL; + } + newsize = newnmemb * size; + + if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { + errno = EINVAL; + return NULL; + } + oldsize = oldnmemb * size; + + /* + * 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/libpam/modules/pam_krb5/Makefile b/lib/libpam/modules/pam_krb5/Makefile index b537bf37b7f3..c1792b5fb61d 100644 --- a/lib/libpam/modules/pam_krb5/Makefile +++ b/lib/libpam/modules/pam_krb5/Makefile @@ -32,7 +32,7 @@ SRCDIR= ${SRCTOP}/contrib/pam-krb5 ${SRCDIR}/pam-util \ ${SRCDIR} -PACKAGE= krb5 +PACKAGE= kerberos LIB= pam_krb5 LIBADD= com_err krb5 diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c index e4123fe02211..d8e60075e103 100644 --- a/lib/libpfctl/libpfctl.c +++ b/lib/libpfctl/libpfctl.c @@ -3348,6 +3348,11 @@ pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter, return (e.error); } +static struct snl_attr_parser ap_clr_addrs[] = { + { .type = PF_T_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint64 }, +}; +SNL_DECLARE_PARSER(clr_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_clr_addrs); + int pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter, int *ndel, int flags) @@ -3380,7 +3385,7 @@ pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter, return (ENXIO); while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) { - if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &del)) + if (!snl_parse_nlmsg(&h->ss, hdr, &clr_addrs_parser, &del)) continue; if (ndel) *ndel = (uint32_t)del; 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/accept.2 b/lib/libsys/accept.2 index 53926b3153d2..2da2af066a5b 100644 --- a/lib/libsys/accept.2 +++ b/lib/libsys/accept.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 9, 2014 +.Dd May 17, 2025 .Dt ACCEPT 2 .Os .Sh NAME @@ -85,6 +85,13 @@ and the close-on-exec flag on the new file descriptor can be set via the flag in the .Fa flags argument. +Similarly, the +.Dv O_CLOFORK +property can be set via the +.Dv SOCK_CLOFORK +flag in the +.Fa flags +argument. .Pp If no pending connections are present on the queue, and the original socket @@ -234,3 +241,8 @@ The .Fn accept4 system call appeared in .Fx 10.0 . +.Pp +The +.Dv SOCK_CLOFORK +flag appeared in +.Fx 15.0 . diff --git a/lib/libsys/closefrom.2 b/lib/libsys/closefrom.2 index aaa4c55607ac..1885a6fdeaa8 100644 --- a/lib/libsys/closefrom.2 +++ b/lib/libsys/closefrom.2 @@ -23,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 3, 2022 +.Dd May 17, 2025 .Dt CLOSEFROM 2 .Os .Sh NAME @@ -59,6 +59,8 @@ Supported .Bl -tag -width ".Dv CLOSE_RANGE_CLOEXEC" .It Dv CLOSE_RANGE_CLOEXEC Set the close-on-exec flag on descriptors in the range instead of closing them. +.It Dv CLOSE_RANGE_CLOFORK +Set the close-on-fork flag on descriptors in the range instead of closing them. .El .Sh RETURN VALUES Upon successful completion, @@ -90,3 +92,8 @@ The .Fn closefrom function first appeared in .Fx 8.0 . +.Pp +The +.Dv CLOSE_RANGE_CLOFORK +flag appeared in +.Fx 15.0 . diff --git a/lib/libsys/execve.2 b/lib/libsys/execve.2 index 5a35980e9555..dc85b9321e48 100644 --- a/lib/libsys/execve.2 +++ b/lib/libsys/execve.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 26, 2022 +.Dd July 02, 2025 .Dt EXECVE 2 .Os .Sh NAME @@ -127,7 +127,10 @@ flag is set (see and .Xr fcntl 2 ) . Descriptors that remain open are unaffected by -.Fn execve . +.Fn execve , +except those with the close-on-fork flag +.Dv FD_CLOFORK +which is cleared from all file descriptors. If any of the standard descriptors (0, 1, and/or 2) are closed at the time .Fn execve diff --git a/lib/libsys/fcntl.2 b/lib/libsys/fcntl.2 index 604de43e5e8c..d67c38cfbc6c 100644 --- a/lib/libsys/fcntl.2 +++ b/lib/libsys/fcntl.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd June 5, 2025 +.Dd June 24, 2025 .Dt FCNTL 2 .Os .Sh NAME @@ -81,6 +81,13 @@ to remain open across .Xr execve 2 system calls. .It +The fork-on-exec flag +.Dv FD_CLOFORK +associated with the new file descriptor is cleared, so the file descriptor is +to remain open across +.Xr fork 2 +system calls. +.It The .Dv FD_RESOLVE_BENEATH flag, described below, will be set if it was set on the original @@ -95,6 +102,15 @@ flag associated with the new file descriptor is set, so the file descriptor is closed when .Xr execve 2 system call executes. +.It Dv F_DUPFD_CLOFORK +Like +.Dv F_DUPFD , +but the +.Dv FD_CLOFORK +flag associated with the new file descriptor is set, so the file descriptor +is closed when +.Xr fork 2 +system call executes. .It Dv F_DUP2FD It is functionally equivalent to .Bd -literal -offset indent @@ -117,6 +133,11 @@ Use .Fn dup2 instead of .Dv F_DUP2FD . +.It Dv F_DUP3FD +Used to implement the +.Fn dup3 +call. +Do not use it. .It Dv F_GETFD Get the flags associated with the file descriptor .Fa fd . @@ -128,6 +149,10 @@ The file will be closed upon execution of .Fa ( arg is ignored). Otherwise, the file descriptor will remain open. +.It Dv FD_CLOFORK +The file will be closed upon execution of the +.Fn fork +family of system calls. .It Dv FD_RESOLVE_BENEATH All path name lookups relative to that file descriptor will behave as if the lookup had @@ -153,7 +178,8 @@ descriptor to also have the flag set. Set flags associated with .Fa fd . The available flags are -.Dv FD_CLOEXEC +.Dv FD_CLOEXEC , +.Dv FD_CLOFORK and .Dv FD_RESOLVE_BENEATH . The @@ -551,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 @@ -785,8 +811,10 @@ for the reasons as stated in .Sh STANDARDS The .Dv F_DUP2FD -constant is non portable. -It is provided for compatibility with AIX and Solaris. +and +.Dv F_DUP3FD +constants are not portable. +They are provided for compatibility with AIX and Solaris. .Pp Per .St -susv4 , @@ -811,3 +839,10 @@ The .Dv F_DUP2FD constant first appeared in .Fx 7.1 . +.Pp +The +.Dv F_DUPFD_CLOFORK +and +.Dv F_DUP3FD +flags appeared in +.Fx 15.0 . 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/fork.2 b/lib/libsys/fork.2 index 7d548a42890d..e59b208a9ff5 100644 --- a/lib/libsys/fork.2 +++ b/lib/libsys/fork.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 5, 2021 +.Dd May 17, 2024 .Dt FORK 2 .Os .Sh NAME @@ -68,6 +68,16 @@ by the parent. This descriptor copying is also used by the shell to establish standard input and output for newly created processes as well as to set up pipes. +Any file descriptors that were marked with the close-on-fork flag, +.Dv FD_CLOFORK +.Po see +.Fn fcntl 2 +and +.Dv O_CLOFORK +in +.Fn open 2 +.Pc , +will not be present in the child process, but remain open in the parent. .It The child process' resource utilizations are set to 0; see 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/getsockopt.2 b/lib/libsys/getsockopt.2 index 8839b61597a2..3867824681d7 100644 --- a/lib/libsys/getsockopt.2 +++ b/lib/libsys/getsockopt.2 @@ -593,6 +593,15 @@ specified amount of time has elapsed since the initial call to If .Fa sp_fd is -1, the socket will be unspliced immediately. +A successful +.Xr select 2 , +.Xr poll 2 , +or +.Xr kqueue 2 +operation testing the ability to read from the source socket indicates +that the splicing has terminated and at least one byte is available for +reading. +When one of the sockets gets closed, splicing ends. .Pp When passed to .Fn getsockopt , diff --git a/lib/libsys/mkdir.2 b/lib/libsys/mkdir.2 index e1f1624cebc4..100f44d1dcf9 100644 --- a/lib/libsys/mkdir.2 +++ b/lib/libsys/mkdir.2 @@ -176,4 +176,4 @@ system call appeared in The .Fn mkdir system call appeared in -.At v1 . +.Bx 4.2 . diff --git a/lib/libsys/open.2 b/lib/libsys/open.2 index 84c4f02fce8a..a0e905a8f375 100644 --- a/lib/libsys/open.2 +++ b/lib/libsys/open.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 3, 2025 +.Dd May 17, 2025 .Dt OPEN 2 .Os .Sh NAME @@ -195,6 +195,9 @@ error if file is not a directory .It Dv O_CLOEXEC automatically close file on .Xr execve 2 +.It Dv O_CLOFORK +automatically close file on any child process created with +.Fn fork 2 .It Dv O_VERIFY verify the contents of the file with .Xr mac_veriexec 4 @@ -360,6 +363,27 @@ may be used to set .Dv FD_CLOEXEC flag for the newly returned file descriptor. .Pp +.Dv O_CLOFORK +may be used to set +.Dv FD_CLOFORK +flag for the newly returned file descriptor. +The file will be closed on any child process created with +.Fn fork 2 , +.Fn vfork 2 +or +.Fn rfork 2 +with the +.Dv RFFDG +flag, remaining open in the parent. +Both the +.Dv O_CLOEXEC +and +.Dv O_CLOFORK +flags can be modified with the +.Dv F_SETFD +.Fn fcntl 2 +command. +.Pp .Dv O_VERIFY may be used to indicate to the kernel that the contents of the file should be verified before allowing the open to proceed. @@ -846,6 +870,9 @@ function was introduced in appeared in 13.0. .Dv O_NAMEDATTR appeared in 15.0. +.Dv O_CLOFORK +appeared in +.Fx 15.0 . .Sh BUGS The .Fa mode diff --git a/lib/libsys/pipe.2 b/lib/libsys/pipe.2 index 9531c9717395..37d6eba420de 100644 --- a/lib/libsys/pipe.2 +++ b/lib/libsys/pipe.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 1, 2017 +.Dd May 17, 2025 .Dt PIPE 2 .Os .Sh NAME @@ -64,6 +64,8 @@ list, defined in .Bl -tag -width ".Dv O_NONBLOCK" .It Dv O_CLOEXEC Set the close-on-exec flag for the new file descriptors. +.It Dv O_CLOFORK +Set the close-on-fork flag for the new file descriptors. .It Dv O_NONBLOCK Set the non-blocking flag for the ends of the pipe. .El @@ -173,3 +175,8 @@ function became a wrapper around .Fn pipe2 in .Fx 11.0 . +.Pp +The +.Dv O_CLOFORK +flag appeared in +.Fx 15.0 . diff --git a/lib/libsys/recv.2 b/lib/libsys/recv.2 index f3ee60b75663..b78cd70b8a1d 100644 --- a/lib/libsys/recv.2 +++ b/lib/libsys/recv.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 30, 2022 +.Dd May 17, 2025 .Dt RECV 2 .Os .Sh NAME @@ -164,6 +164,7 @@ one or more of the values: .It Dv MSG_WAITALL Ta wait for full request or error .It Dv MSG_DONTWAIT Ta do not block .It Dv MSG_CMSG_CLOEXEC Ta set received fds close-on-exec +.It Dv MSG_CMSG_CLOFORK Ta set received fds close-on-fork .It Dv MSG_WAITFORONE Ta do not block after receiving the first message (only for .Fn recvmmsg diff --git a/lib/libsys/socket.2 b/lib/libsys/socket.2 index a383cbcc4d80..b211611c6354 100644 --- a/lib/libsys/socket.2 +++ b/lib/libsys/socket.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 15, 2023 +.Dd May 17, 2025 .Dt SOCKET 2 .Os .Sh NAME @@ -121,6 +121,7 @@ argument: .Pp .Bd -literal -offset indent -compact SOCK_CLOEXEC Set close-on-exec on the new descriptor, +SOCK_CLOFORK Set close-on-fork on the new descriptor, SOCK_NONBLOCK Set non-blocking mode on the new socket .Ed .Pp @@ -331,7 +332,10 @@ argument of .Fn socket . The .Dv SOCK_CLOEXEC -flag is expected to conform to the next revision of the +and +.Dv SOCK_CLOFORK +flags are expected to conform to +.St -p1003.1-2024 . .Tn POSIX standard. The @@ -347,3 +351,8 @@ The .Fn socket system call appeared in .Bx 4.2 . +.Pp +The +.Dv SOCK_CLOFORK +flag appeared in +.Fx 15.0 . diff --git a/lib/libsys/socketpair.2 b/lib/libsys/socketpair.2 index 5874a0791f4d..60dec74f9cc2 100644 --- a/lib/libsys/socketpair.2 +++ b/lib/libsys/socketpair.2 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 10, 2018 +.Dd May 17, 2025 .Dt SOCKETPAIR 2 .Os .Sh NAME @@ -56,7 +56,8 @@ and The two sockets are indistinguishable. .Pp The -.Dv SOCK_CLOEXEC +.Dv SOCK_CLOEXEC , +.Dv SOCK_CLOFORK and .Dv SOCK_NONBLOCK flags in the 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/libsysdecode/flags.c b/lib/libsysdecode/flags.c index dc09c5747968..f8e26e6a9dae 100644 --- a/lib/libsysdecode/flags.c +++ b/lib/libsysdecode/flags.c @@ -196,7 +196,7 @@ sysdecode_vmprot(FILE *fp, int type, int *rem) } static struct name_table sockflags[] = { - X(SOCK_CLOEXEC) X(SOCK_NONBLOCK) XEND + X(SOCK_CLOEXEC) X(SOCK_CLOFORK) X(SOCK_NONBLOCK) XEND }; bool @@ -206,16 +206,17 @@ sysdecode_socket_type(FILE *fp, int type, int *rem) uintmax_t val; bool printed; - str = lookup_value(socktype, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)); + str = lookup_value(socktype, + type & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK)); if (str != NULL) { fputs(str, fp); *rem = 0; printed = true; } else { - *rem = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK); + *rem = type & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK); printed = false; } - val = type & (SOCK_CLOEXEC | SOCK_NONBLOCK); + val = type & (SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK); print_mask_part(fp, sockflags, &val, &printed); return (printed); } @@ -563,7 +564,7 @@ sysdecode_nfssvc_flags(int flags) } static struct name_table pipe2flags[] = { - X(O_CLOEXEC) X(O_NONBLOCK) XEND + X(O_CLOEXEC) X(O_CLOFORK) X(O_NONBLOCK) XEND }; bool @@ -873,7 +874,7 @@ sysdecode_fcntl_cmd(int cmd) } static struct name_table fcntl_fd_arg[] = { - X(FD_CLOEXEC) X(0) XEND + X(FD_CLOEXEC) X(FD_CLOFORK) X(0) XEND }; bool diff --git a/lib/libsysdecode/sysdecode_fcntl_arg.3 b/lib/libsysdecode/sysdecode_fcntl_arg.3 index ee3a030a79e4..d5648ce0adc3 100644 --- a/lib/libsysdecode/sysdecode_fcntl_arg.3 +++ b/lib/libsysdecode/sysdecode_fcntl_arg.3 @@ -54,7 +54,8 @@ are determined by .It Sy Command Ta Fa arg Sy Type Ta Sy Output Format .It .It Dv F_SETFD Ta Vt int Ta -.Dq FD_CLOEXEC +.Dq FD_CLOEXEC , +.Dq FD_CLOFORK or the value of .Fa arg in the indicated 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/libutil/Makefile b/lib/libutil/Makefile index 0639745d08fc..2d92c5ba1916 100644 --- a/lib/libutil/Makefile +++ b/lib/libutil/Makefile @@ -38,6 +38,7 @@ MAN+= cpuset.3 expand_number.3 flopen.3 fparseln.3 ftime.3 getlocalbase.3 \ property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \ _secure_path.3 trimdomain.3 uucplock.3 pw_util.3 MAN+= login.conf.5 +MLINKS+=cpuset.3 domainset_parselist.3 MLINKS+=flopen.3 flopenat.3 MLINKS+=kld.3 kld_isloaded.3 kld.3 kld_load.3 MLINKS+=login_auth.3 auth_cat.3 login_auth.3 auth_checknologin.3 diff --git a/lib/libutil/cpuset.3 b/lib/libutil/cpuset.3 index be29d5309ef0..47dffd209ee6 100644 --- a/lib/libutil/cpuset.3 +++ b/lib/libutil/cpuset.3 @@ -22,21 +22,22 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 31, 2017 +.Dd June 24, 2025 .Dt CPUSET 3 .Os .Sh NAME -.Nm cpuset_parselist -.Nd utility functions for -.Xr cpuset 2 -handling +.Nm cpuset_parselist , +.Nm domainset_parselist +.Nd utility functions for cpuset(2) handling .Sh LIBRARY .Lb libutil .Sh SYNOPSIS .In sys/cpuset.h .In libutil.h .Ft int -.Fn cpuset_parselist "const char *cpu-list" "cpuset_t *mask" +.Fn cpuset_parselist "const char *cpu_list" "cpuset_t *mask" +.Ft int +.Fn domainset_parselist "const char *domain_policy" "domainset_t *domain_mask" "int *policyp" .Sh DESCRIPTION The .Fn cpuset_parselist @@ -52,6 +53,27 @@ numbers. A special list of .Dq all may be specified in which case the list includes all CPUs from the root set. +.Pp +The +.Fn domainset_parselist +function parses a +.Xr domainset 9 +memory domain allocation policy +specified by +.Va domain_policy +filling the +.Va domain_mask +and the +.Va policyp . +A valid +.Va domain_policy +is formatted as +.Ar policy:domain-list . +See the +.Ar -n +flag in +.Xr cpuset 1 +for a list of valid domain policies. .Sh RETURN VALUES Return values can be the following .Bl -tag -width Er @@ -60,19 +82,30 @@ The parsing was successful .It Dv CPUSET_PARSE_ERROR The .Va cpu-list +or +.Va domain-policy format is invalid .It Dv CPUSET_PARSE_GETAFFINITY The .Xr cpuset_getaffinity 2 call has failed .It Dv CPUSET_PARSE_INVALID_CPU -The number of supported CPUs has been exceeded. +The number of supported CPUs or NUMA domains has been exceeded. The maximum number being -.Va CPU_SETSIZE . +.Va CPU_SETSIZE +and +.Va DOMAINSET_SETSIZE +respectively. +.It Dv CPUSET_PARSE_GETDOMAIN +The +.Xr cpuset_getdomain 2 +call has failed .El .Sh SEE ALSO .Xr cpuset 1 , .Xr cpuset 2 , -.Xr cpuset 9 +.Xr numa 4 , +.Xr cpuset 9 , +.Xr domainset 9 .Sh AUTHORS .An Jeffrey Roberson Aq Mt jeff@FreeBSD.org diff --git a/lib/libutil/cpuset.c b/lib/libutil/cpuset.c index 3c374bfa6cac..d4840af7e175 100644 --- a/lib/libutil/cpuset.c +++ b/lib/libutil/cpuset.c @@ -27,34 +27,48 @@ * SUCH DAMAGE. */ +#include <sys/cdefs.h> +#define _WANT_FREEBSD_BITSET + #include <sys/types.h> #include <sys/cpuset.h> +#include <sys/domainset.h> #include <stdlib.h> #include <string.h> #include <libutil.h> #include <ctype.h> -int -cpuset_parselist(const char *list, cpuset_t *mask) +struct numa_policy { + const char *name; + int policy; +}; + +static const struct numa_policy policies[] = { + { "round-robin", DOMAINSET_POLICY_ROUNDROBIN }, + { "rr", DOMAINSET_POLICY_ROUNDROBIN }, + { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH }, + { "ft", DOMAINSET_POLICY_FIRSTTOUCH }, + { "prefer", DOMAINSET_POLICY_PREFER }, + { "interleave", DOMAINSET_POLICY_INTERLEAVE}, + { "il", DOMAINSET_POLICY_INTERLEAVE}, + { NULL, DOMAINSET_POLICY_INVALID } +}; + +static int +parselist(const char *list, struct bitset *mask, int size) { enum { NONE, NUM, DASH } state; int lastnum; int curnum; const char *l; - if (strcasecmp(list, "all") == 0) { - if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, - sizeof(*mask), mask) != 0) - return (CPUSET_PARSE_GETAFFINITY); - return (CPUSET_PARSE_OK); - } state = NONE; curnum = lastnum = 0; for (l = list; *l != '\0';) { if (isdigit(*l)) { curnum = atoi(l); - if (curnum > CPU_SETSIZE) + if (curnum >= size) return (CPUSET_PARSE_INVALID_CPU); while (isdigit(*l)) l++; @@ -65,7 +79,7 @@ cpuset_parselist(const char *list, cpuset_t *mask) break; case DASH: for (; lastnum <= curnum; lastnum++) - CPU_SET(lastnum, mask); + BIT_SET(size, lastnum, mask); state = NONE; break; case NUM: @@ -80,7 +94,7 @@ cpuset_parselist(const char *list, cpuset_t *mask) case NONE: break; case NUM: - CPU_SET(curnum, mask); + BIT_SET(size, curnum, mask); state = NONE; break; case DASH: @@ -102,7 +116,7 @@ cpuset_parselist(const char *list, cpuset_t *mask) case NONE: break; case NUM: - CPU_SET(curnum, mask); + BIT_SET(size, curnum, mask); break; case DASH: goto parserr; @@ -111,3 +125,63 @@ cpuset_parselist(const char *list, cpuset_t *mask) parserr: return (CPUSET_PARSE_ERROR); } + +/* + * permissively parse policy:domain list + * allow: + * round-robin:0-4 explicit + * round-robin:all explicit root domains + * 0-4 implicit root policy + * round-robin implicit root domains + * all explicit root domains and implicit policy + */ +int +domainset_parselist(const char *list, domainset_t *mask, int *policyp) +{ + domainset_t rootmask; + const struct numa_policy *policy; + const char *l; + int p; + + /* + * Use the rootset's policy as the default for unspecified policies. + */ + if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(rootmask), &rootmask, &p) != 0) + return (CPUSET_PARSE_GETDOMAIN); + + if (list == NULL || strcasecmp(list, "all") == 0 || *list == '\0') { + *policyp = p; + DOMAINSET_COPY(&rootmask, mask); + return (CPUSET_PARSE_OK); + } + + l = list; + for (policy = &policies[0]; policy->name != NULL; policy++) { + if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) { + p = policy->policy; + l += strlen(policy->name); + if (*l != ':' && *l != '\0') + return (CPUSET_PARSE_ERROR); + if (*l == ':') + l++; + break; + } + } + *policyp = p; + + return (parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE)); +} + +int +cpuset_parselist(const char *list, cpuset_t *mask) +{ + if (strcasecmp(list, "all") == 0) { + if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(*mask), mask) != 0) + return (CPUSET_PARSE_GETAFFINITY); + return (CPUSET_PARSE_OK); + } + + return (parselist(list, (struct bitset *)mask, CPU_SETSIZE)); +} diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h index 919855184caf..7d8bfdf67fac 100644 --- a/lib/libutil/libutil.h +++ b/lib/libutil/libutil.h @@ -213,7 +213,13 @@ int cpuset_parselist(const char *list, cpuset_t *mask); #define CPUSET_PARSE_OK 0 #define CPUSET_PARSE_GETAFFINITY -1 #define CPUSET_PARSE_ERROR -2 -#define CPUSET_PARSE_INVALID_CPU -3 +#define CPUSET_PARSE_OUT_OF_RANGE -3 +#define CPUSET_PARSE_GETDOMAIN -4 +#define CPUSET_PARSE_INVALID_CPU CPUSET_PARSE_OUT_OF_RANGE /* backwards compat */ +#endif + +#ifdef _SYS_DOMAINSET_H_ +int domainset_parselist(const char *list, domainset_t *mask, int *policyp); #endif __END_DECLS diff --git a/lib/libvmmapi/Makefile b/lib/libvmmapi/Makefile index 1866c8fa5e7c..6dd0deeaa9c0 100644 --- a/lib/libvmmapi/Makefile +++ b/lib/libvmmapi/Makefile @@ -1,6 +1,6 @@ PACKAGE=lib${LIB} LIB= vmmapi -SHLIB_MAJOR= 6 +SHLIB_MAJOR= 7 SRCS= vmmapi.c INCS= vmmapi.h diff --git a/lib/libvmmapi/internal.h b/lib/libvmmapi/internal.h index aa7b1d8e6a93..4afe1cab3460 100644 --- a/lib/libvmmapi/internal.h +++ b/lib/libvmmapi/internal.h @@ -8,12 +8,7 @@ #define __VMMAPI_INTERNAL_H__ #include <sys/types.h> - -enum { - VM_MEMSEG_LOW, - VM_MEMSEG_HIGH, - VM_MEMSEG_COUNT, -}; +#include <dev/vmm/vmm_mem.h> struct vmctx { int fd; /* device file descriptor */ @@ -21,7 +16,9 @@ struct vmctx { struct { vm_paddr_t base; vm_size_t size; - } memsegs[VM_MEMSEG_COUNT]; + } memsegs[VM_MAX_MEMSEGS]; + size_t lowmem_size; + size_t highmem_size; int memflags; char *baseaddr; char *name; diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index a1a5d56ff8a2..77f0f8f5c581 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -28,13 +28,14 @@ #include <sys/param.h> #include <sys/capsicum.h> +#include <sys/cpuset.h> +#include <sys/domainset.h> #include <sys/sysctl.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/linker.h> #include <sys/module.h> #include <sys/_iovec.h> -#include <sys/cpuset.h> #include <capsicum_helpers.h> #include <err.h> @@ -322,8 +323,8 @@ vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr, { *guest_baseaddr = ctx->baseaddr; - *lowmem_size = ctx->memsegs[VM_MEMSEG_LOW].size; - *highmem_size = ctx->memsegs[VM_MEMSEG_HIGH].size; + *lowmem_size = ctx->lowmem_size; + *highmem_size = ctx->highmem_size; return (0); } @@ -379,7 +380,8 @@ cmpseg(size_t len, const char *str, size_t len2, const char *str2) } static int -vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name) +vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name, + int ds_policy, domainset_t *ds_mask, size_t ds_size) { struct vm_memseg memseg; size_t n; @@ -407,6 +409,13 @@ vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name) bzero(&memseg, sizeof(struct vm_memseg)); memseg.segid = segid; memseg.len = len; + if (ds_mask == NULL) { + memseg.ds_policy = DOMAINSET_POLICY_INVALID; + } else { + memseg.ds_policy = ds_policy; + memseg.ds_mask = ds_mask; + memseg.ds_mask_size = ds_size; + } if (name != NULL) { n = strlcpy(memseg.name, name, sizeof(memseg.name)); if (n >= sizeof(memseg.name)) { @@ -442,13 +451,14 @@ vm_get_memseg(struct vmctx *ctx, int segid, size_t *lenp, char *namebuf, } static int -setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base) +map_memory_segment(struct vmctx *ctx, int segid, vm_paddr_t gpa, size_t len, + size_t segoff, char *base) { char *ptr; int error, flags; /* Map 'len' bytes starting at 'gpa' in the guest address space */ - error = vm_mmap_memseg(ctx, gpa, VM_SYSMEM, gpa, len, PROT_ALL); + error = vm_mmap_memseg(ctx, gpa, segid, segoff, len, PROT_ALL); if (error) return (error); @@ -464,65 +474,136 @@ setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base) return (0); } +/* + * Allocates and maps virtual machine memory segments according + * to the NUMA topology specified by the 'doms' array. + * + * The domains are laid out sequentially in the guest's physical address space. + * The [VM_LOWMEM_LIMIT, VM_HIGHMEM_BASE) address range is skipped and + * left unmapped. + */ int -vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) +vm_setup_memory_domains(struct vmctx *ctx, enum vm_mmap_style vms, + struct vm_mem_domain *doms, int ndoms) { - size_t objsize, len; - vm_paddr_t gpa; + size_t low_len, len, totalsize; + struct vm_mem_domain *dom; + struct vm_memseg memseg; char *baseaddr, *ptr; - int error; + int error, i, segid; + vm_paddr_t gpa; + /* Sanity checks. */ assert(vms == VM_MMAP_ALL); - - /* - * If 'memsize' cannot fit entirely in the 'lowmem' segment then create - * another 'highmem' segment above VM_HIGHMEM_BASE for the remainder. - */ - if (memsize > VM_LOWMEM_LIMIT) { - ctx->memsegs[VM_MEMSEG_LOW].size = VM_LOWMEM_LIMIT; - ctx->memsegs[VM_MEMSEG_HIGH].size = memsize - VM_LOWMEM_LIMIT; - objsize = VM_HIGHMEM_BASE + ctx->memsegs[VM_MEMSEG_HIGH].size; - } else { - ctx->memsegs[VM_MEMSEG_LOW].size = memsize; - ctx->memsegs[VM_MEMSEG_HIGH].size = 0; - objsize = memsize; + if (doms == NULL || ndoms <= 0 || ndoms > VM_MAXMEMDOM) { + errno = EINVAL; + return (-1); } - error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL); - if (error) - return (error); + /* Calculate total memory size. */ + totalsize = 0; + for (i = 0; i < ndoms; i++) + totalsize += doms[i].size; + + if (totalsize > VM_LOWMEM_LIMIT) + totalsize = VM_HIGHMEM_BASE + (totalsize - VM_LOWMEM_LIMIT); /* * Stake out a contiguous region covering the guest physical memory * and the adjoining guard regions. */ - len = VM_MMAP_GUARD_SIZE + objsize + VM_MMAP_GUARD_SIZE; + len = VM_MMAP_GUARD_SIZE + totalsize + VM_MMAP_GUARD_SIZE; ptr = mmap(NULL, len, PROT_NONE, MAP_GUARD | MAP_ALIGNED_SUPER, -1, 0); if (ptr == MAP_FAILED) return (-1); - baseaddr = ptr + VM_MMAP_GUARD_SIZE; - if (ctx->memsegs[VM_MEMSEG_HIGH].size > 0) { - gpa = VM_HIGHMEM_BASE; - len = ctx->memsegs[VM_MEMSEG_HIGH].size; - error = setup_memory_segment(ctx, gpa, len, baseaddr); - if (error) - return (error); - } - if (ctx->memsegs[VM_MEMSEG_LOW].size > 0) { - gpa = 0; - len = ctx->memsegs[VM_MEMSEG_LOW].size; - error = setup_memory_segment(ctx, gpa, len, baseaddr); - if (error) - return (error); - } + /* + * Allocate and map memory segments for the virtual machine. + */ + gpa = VM_LOWMEM_LIMIT > 0 ? 0 : VM_HIGHMEM_BASE; + ctx->lowmem_size = 0; + ctx->highmem_size = 0; + for (i = 0; i < ndoms; i++) { + segid = VM_SYSMEM + i; + dom = &doms[i]; + + /* + * Check if the memory segment already exists. + * If 'ndoms' is greater than one, refuse to proceed if the + * memseg already exists. If only one domain was requested, use + * the existing segment to preserve the behaviour of the previous + * implementation. + * + * Splitting existing memory segments is tedious and + * error-prone, which is why we don't support NUMA + * domains for bhyveload(8)-loaded VMs. + */ + error = vm_get_memseg(ctx, segid, &len, memseg.name, + sizeof(memseg.name)); + if (error == 0 && len != 0) { + if (ndoms != 1) { + errno = EEXIST; + return (-1); + } else + doms[0].size = len; + } else { + error = vm_alloc_memseg(ctx, segid, dom->size, NULL, + dom->ds_policy, dom->ds_mask, dom->ds_size); + if (error) + return (error); + } + /* + * If a domain is split by VM_LOWMEM_LIMIT then break + * its segment mapping into two parts, one below VM_LOWMEM_LIMIT + * and one above VM_HIGHMEM_BASE. + */ + if (gpa <= VM_LOWMEM_LIMIT && + gpa + dom->size > VM_LOWMEM_LIMIT) { + low_len = VM_LOWMEM_LIMIT - gpa; + error = map_memory_segment(ctx, segid, gpa, low_len, 0, + baseaddr); + if (error) + return (error); + ctx->lowmem_size = VM_LOWMEM_LIMIT; + /* Map the remainder. */ + gpa = VM_HIGHMEM_BASE; + len = dom->size - low_len; + error = map_memory_segment(ctx, segid, gpa, len, + low_len, baseaddr); + if (error) + return (error); + } else { + len = dom->size; + error = map_memory_segment(ctx, segid, gpa, len, 0, + baseaddr); + if (error) + return (error); + } + if (gpa <= VM_LOWMEM_LIMIT) + ctx->lowmem_size += len; + else + ctx->highmem_size += len; + gpa += len; + } ctx->baseaddr = baseaddr; return (0); } +int +vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms) +{ + struct vm_mem_domain dom0; + + memset(&dom0, 0, sizeof(dom0)); + dom0.ds_policy = DOMAINSET_POLICY_INVALID; + dom0.size = memsize; + + return (vm_setup_memory_domains(ctx, vms, &dom0, 1)); +} + /* * Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in * the lowmem or highmem regions. @@ -535,13 +616,13 @@ vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len) { vm_size_t lowsize, highsize; - lowsize = ctx->memsegs[VM_MEMSEG_LOW].size; + lowsize = ctx->lowmem_size; if (lowsize > 0) { if (gaddr < lowsize && len <= lowsize && gaddr + len <= lowsize) return (ctx->baseaddr + gaddr); } - highsize = ctx->memsegs[VM_MEMSEG_HIGH].size; + highsize = ctx->highmem_size; if (highsize > 0 && gaddr >= VM_HIGHMEM_BASE) { if (gaddr < VM_HIGHMEM_BASE + highsize && len <= highsize && gaddr + len <= VM_HIGHMEM_BASE + highsize) @@ -559,12 +640,12 @@ vm_rev_map_gpa(struct vmctx *ctx, void *addr) offaddr = (char *)addr - ctx->baseaddr; - lowsize = ctx->memsegs[VM_MEMSEG_LOW].size; + lowsize = ctx->lowmem_size; if (lowsize > 0) if (offaddr <= lowsize) return (offaddr); - highsize = ctx->memsegs[VM_MEMSEG_HIGH].size; + highsize = ctx->highmem_size; if (highsize > 0) if (offaddr >= VM_HIGHMEM_BASE && offaddr < VM_HIGHMEM_BASE + highsize) @@ -583,8 +664,7 @@ vm_get_name(struct vmctx *ctx) size_t vm_get_lowmem_size(struct vmctx *ctx) { - - return (ctx->memsegs[VM_MEMSEG_LOW].size); + return (ctx->lowmem_size); } vm_paddr_t @@ -597,8 +677,7 @@ vm_get_highmem_base(struct vmctx *ctx __unused) size_t vm_get_highmem_size(struct vmctx *ctx) { - - return (ctx->memsegs[VM_MEMSEG_HIGH].size); + return (ctx->highmem_size); } void * @@ -616,7 +695,7 @@ vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len) goto done; } - error = vm_alloc_memseg(ctx, segid, len, name); + error = vm_alloc_memseg(ctx, segid, len, name, 0, NULL, 0); if (error) goto done; diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index 440064ad13cb..b637c45d1eff 100644 --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -40,7 +40,7 @@ * API version for out-of-tree consumers like grub-bhyve for making compile * time decisions. */ -#define VMMAPI_VERSION 0200 /* 2 digit major followed by 2 digit minor */ +#define VMMAPI_VERSION 0300 /* 2 digit major followed by 2 digit minor */ struct iovec; struct vcpu; @@ -64,16 +64,12 @@ enum vm_mmap_style { #define VM_MEM_F_INCORE 0x01 /* include guest memory in core file */ #define VM_MEM_F_WIRED 0x02 /* guest memory is wired */ -/* - * Identifiers for memory segments: - * - vm_setup_memory() uses VM_SYSMEM for the system memory segment. - * - the remaining identifiers can be used to create devmem segments. - */ -enum { - VM_SYSMEM, - VM_BOOTROM, - VM_FRAMEBUFFER, - VM_PCIROM, +/* Memory size and allocation policy for a single NUMA domain. */ +struct vm_mem_domain { + size_t size; + int ds_policy; + domainset_t *ds_mask; + size_t ds_size; }; __BEGIN_DECLS @@ -127,7 +123,9 @@ struct vcpu *vm_vcpu_open(struct vmctx *ctx, int vcpuid); void vm_vcpu_close(struct vcpu *vcpu); int vcpu_id(struct vcpu *vcpu); int vm_parse_memsize(const char *optarg, size_t *memsize); -int vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s); +int vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s); +int vm_setup_memory_domains(struct vmctx *ctx, enum vm_mmap_style s, + struct vm_mem_domain *doms, int ndoms); void *vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len); /* inverse operation to vm_map_gpa - extract guest address from host pointer */ vm_paddr_t vm_rev_map_gpa(struct vmctx *ctx, void *addr); 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 |